Wie man aufhört, sich Sorgen zu machen, und anfÀngt, ohne Monolith zu leben

Wie man aufhört, sich Sorgen zu machen, und anfÀngt, ohne Monolith zu leben

Wir alle lieben Geschichten. Es gefĂ€llt uns, am Lagerfeuer zu sitzen und von unseren frĂŒheren Siegen, KĂ€mpfen oder einfach von unseren Erfahrungen zu erzĂ€hlen.

Heute ist genau so ein Tag. Und auch wenn Sie jetzt nicht am Lagerfeuer sitzen, haben wir eine Geschichte fĂŒr Sie. Eine Geschichte darĂŒber, wie wir begonnen haben, mit dem Speicher auf Tarantool zu arbeiten.

Vor langer Zeit gab es in unserem Unternehmen ein paar „Monolithen“ und eine gemeinsame „Decke“, der diese Monolithen langsam, aber sicher nĂ€her kamen und den Flug unseres Unternehmens, unser Wachstum, einschrĂ€nkten. Und es gab ein klares Bewusstsein: Eines Tages wĂŒrden wir heftig gegen diese Decke stoßen.

Heute herrscht bei uns die Ideologie der Trennung von allem und jedem, angefangen bei der Hardware bis hin zur GeschÀftslogik. Infolgedessen haben wir beispielsweise zwei DCs, die auf netzwerktechnischer Ebene praktisch unabhÀngig sind. Damals war alles jedoch ganz anders.

Heutzutage gibt es eine Vielzahl von Werkzeugen und Mitteln zur Implementierung von Änderungen, wie CI/CD, K8S usw. In der „monolithischen“ Zeit benötigten wir nicht so viele Fremdwörter. Es genĂŒgte, einfach das „Speicherding“ in der Datenbank zu Ă€ndern.

Doch die Zeit schritt voran, und die Anzahl der Anfragen stieg entsprechend, sodass gelegentlich unsere Möglichkeiten ĂŒbertroffen wurden. Mit dem Markteintritt in den GUS-Staaten fiel die Belastung auf dem Prozessor der ersten Monolith-Datenbank nicht unter 90 % und die RPS lagen bei 2400. Und das waren nicht einfach kleine Selektionen, sondern riesige Anfragen mit einer Vielzahl von ÜberprĂŒfungen und JOINs, die fast ĂŒber die HĂ€lfte der Daten im Hintergrund bei großem IO laufen konnten.

Als dann richtige Verkaufsaktionen zum „Black Friday“ begannen – und Wildberries damit einer der ersten in Russland war – wurde die Situation ganz traurig. Denn die Belastung an solchen Tagen steigt um das Dreifache.
Oh, diese „monolithischen Zeiten“! Ich bin mir sicher, dass auch Sie damit konfrontiert waren und immer noch nicht verstehen können, wie das Ihnen passieren konnte.

Was kann man tun – Trends betreffen auch Technologien. Vor etwa 5 Jahren mussten wir einen solchen Trend ĂŒberdenken, der sich in der vorhandenen Website auf .NET und MS SQL-Server manifestierte, die sorgfĂ€ltig die gesamte Logik der Funktionsweise der Website speicherte. Sie speicherte sie so sorgsam, dass das Zerschneiden eines solchen Monolithen ein langwieriges und keineswegs einfaches VergnĂŒgen war.
Eine kleine Bemerkung.

Auf verschiedenen Veranstaltungen sage ich: „Wenn Sie das Monolith nicht zersĂ€gt haben, dann sind Sie nicht gewachsen!“ Ich bin gespannt auf Ihre Meinung dazu, bitte schreiben Sie sie in die Kommentare.

Und es donnert

Kehren wir zu unserem „Kamin“ zurĂŒck. Um die Last der „monolithischen“ FunktionalitĂ€t zu verteilen, haben wir beschlossen, das System in Mikrodienste zu unterteilen, die auf Open-Source-Technologien basieren. Denn deren Skalierung ist zumindest gĂŒnstiger. Und wir waren uns zu 100 % bewusst, dass wir es skalieren mĂŒssen (und das nicht wenig). Denn bereits zu diesem Zeitpunkt hatten wir MĂ€rkte in NachbarlĂ€ndern erschlossen, und die Anzahl der Registrierungen sowie die Anzahl der Bestellungen begann noch stĂ€rker zu wachsen.

Nachdem wir die ersten Kandidaten fĂŒr den Ausstieg aus dem Monolithen in Mikrodienste analysiert hatten, verstanden wir, dass in 80 % der FĂ€lle die Daten in 99 % aus Backoffice-Systemen stammen, wĂ€hrend das Lesen von der Front kommt. Dies betraf in erster Linie zwei wichtige Teilsysteme fĂŒr uns – die Benutzerdaten und das System zur Berechnung der Endpreise von Waren basierend auf Informationen ĂŒber zusĂ€tzliche KundenermĂ€ĂŸigungen und Gutscheine.

Am Rande. Es ist erschreckend sich vorzustellen, aber neben den oben genannten Teilsystemen wurden auch die Produktkataloge, der Warenkorb, das Produktsuchsystem, das Filtersystem fĂŒr die Produktkataloge und verschiedene Empfehlungssysteme aus unserem Monolithen ausgelagert. FĂŒr die Arbeit jedes einzelnen existieren separate Klassen von spezialisierten Systemen, aber einst lebten sie alle in einem „HĂ€uschen“.

Die Daten unserer Kunden wollten wir sofort in ein shardiertes System auslagern. Die Auslagerung der FunktionalitĂ€t zur Berechnung der Endpreise fĂŒr Waren erforderte jedoch eine gute Leseskalierbarkeit, da diese die grĂ¶ĂŸte Belastung in Bezug auf RPS verursachte und fĂŒr die Datenbank am schwierigsten umzusetzen war (sehr viele Daten sind in den Berechnungsprozess involviert).

Infolgedessen entstand ein Schema, das gut mit Tarantool harmonierte.

Zu diesem Zeitpunkt wurden fĂŒr die Arbeit mit Mikrodiensten Modelle gewĂ€hlt, die mehrere Rechenzentren auf virtuellen und physischen Maschinen unterstĂŒtzen. Wie in den Abbildungen gezeigt, wurden Tarantool-Replikationsvarianten sowohl im Master-Master- als auch im Master-Slave-Modus angewendet.

Wie man aufhört, sich Sorgen zu machen, und anfÀngt, ohne Monolith zu leben
Architektur. Variante 1. Benutzerservice

Aktuell sind es 24 Shards, von denen jeder ĂŒber 2 Instanzen (jeweils eine in jedem DC) verfĂŒgt, alle im Master-Master-Modus.

Über der Datenbank befinden sich Anwendungen, die auf die Replikate der Datenbank zugreifen. Die Anwendungen arbeiten ĂŒber unsere benutzerdefinierte Bibliothek mit Tarantool, die die Schnittstelle des Go-Tarantool-Treibers implementiert. Sie sieht alle Replikate und kann sowohl mit dem Master zum Lesen als auch zum Schreiben arbeiten. Im Grunde implementiert sie das Modell des Replikatensatzes, in das Logik zur Auswahl von Replikaten, zur DurchfĂŒhrung von Wiederholungsversuchen, Circuit Breaker und Ratenbegrenzung integriert ist.

Dabei besteht die Möglichkeit, die Auswahlrichtlinie der Replikate im Hinblick auf Shards zu konfigurieren. Zum Beispiel Round-Robin.

Wie man aufhört, sich Sorgen zu machen, und anfÀngt, ohne Monolith zu leben
Architektur. Variante 2. Dienst zur Berechnung der Endkosten eines Produkts

Vor einigen Monaten gingen die meisten Anfragen zur Berechnung der Endkosten von Produkten an einen neuen Dienst, der grundsÀtzlich ohne Datenbanken funktioniert, aber eine Zeit lang wurden 100 % von einem Dienst mit Tarantool im Hintergrund verarbeitet.

Die Datenbank des Dienstes besteht aus 4 Master-Knoten, in die der Synchronisierer Daten sammelt, und jeder dieser Master verteilte die Daten ĂŒber Replikation auf readonly-Replikate. Jeder Master hat ungefĂ€hr 15 solcher Replikate.

Sowohl im ersten als auch im zweiten Schema kann die Anwendung bei Nichterreichbarkeit eines Rechenzentrums die Daten im zweiten erhalten.

Es ist erwĂ€hnenswert, dass die Replikation in Tarantool ziemlich flexibel ist und zur Laufzeit konfiguriert werden kann. In anderen Systemen gab es oft Schwierigkeiten. Zum Beispiel erfordert die Änderung der Parameter max_wal_senders und max_replication_slots in PostgreSQL einen Neustart des Masters, was in einigen FĂ€llen zu VerbindungsabbrĂŒchen zwischen der Anwendung und der Datenbank fĂŒhren kann.

Suchen und finden!

Warum haben wir nicht „wie normale Menschen“ gemacht, sondern einen untypischen Weg gewĂ€hlt? Es kommt darauf an, was man fĂŒr normal hĂ€lt. Viele machen ĂŒberhaupt einen Cluster aus Mongo und verteilen ihn ĂŒber drei geo-verteilte Rechenzentren.

Zu dieser Zeit hatten wir bereits zwei Projekte auf Redis. Das erste war ein Cache, das zweite stellte ein persistentes Speicher fĂŒr nicht allzu kritische Daten dar. Damit hatten wir es ziemlich schwer, teilweise auch wegen unserer Schuld. Manchmal lagen recht große Mengen Daten im SchlĂŒssel, und es wurde dem System gelegentlich schlecht. Dieses System nutzten wir im Master-Slave-Modus. Es gab viele FĂ€lle, in denen etwas mit dem Master passierte und die Replikation fehlschlug.

Das heißt, Redis eignet sich gut fĂŒr zustandslose Aufgaben, aber nicht fĂŒr zustandsbehaftete. GrundsĂ€tzlich konnte es die meisten Aufgaben lösen, aber nur, wenn es sich um SchlĂŒssel-Werte-Lösungen mit ein paar Indizes handelte. Zu diesem Zeitpunkt hatte Redis jedoch erhebliche Probleme mit Persistenz und Replikation. Außerdem gab es Beschwerden ĂŒber die Leistung.

Wir haben ĂŒber MySQL und PostgreSQL nachgedacht. Aber der erste hat sich irgendwie nicht bei uns durchgesetzt, und der zweite ist an sich ein recht komplexes Produkt, weshalb es unpraktisch wĂ€re, auf ihm einfache Dienste aufzubauen.
Wir haben RIAK, Cassandra und sogar grafische Datenbanken ausprobiert. All diese Lösungen sind ziemlich nischenhaft und eigneten sich nicht als allgemeines, universelles Werkzeug zur Erstellung von Diensten.

Letztendlich haben wir uns fĂŒr Tarantool entschieden.

Wir haben ihn in der Version 1.6 kontaktiert. Wir waren an dem Zusammenspiel von SchlĂŒssel-Wert und der FunktionalitĂ€t einer relationalen Datenbank interessiert. Es gibt sekundĂ€re Indizes, Transaktionen und Spaces, das sind wie Tabellen, aber keine einfachen; man kann unterschiedlich viele Spalten darin speichern. Das Killer-Feature von Tarantool waren die sekundĂ€ren Indizes in Kombination mit SchlĂŒssel-Wert und TransaktionsfĂ€higkeit.

Auch die hilfsbereite russischsprachige Community spielte eine Rolle, die bereit war, im Chat zu helfen. Wir haben dies aktiv genutzt und lebten praktisch im Chat. Und man sollte nicht die anstÀndige Persistenz ohne klare Fehler und MÀngel vergessen. Wenn man unsere Geschichte mit Tarantool betrachtet, hatten wir viele Probleme und Schwierigkeiten mit der Replikation, aber wir haben nie Daten aufgrund seiner Schuld verloren!

Die Implementierung begann schwierig.

Zu diesem Zeitpunkt war .NET unser Hauptentwicklungsstapel, fĂŒr den es keinen Connector fĂŒr Tarantool gab. Wir begannen sofort, etwas in Go zu machen. Mit Lua klappte es auch ganz gut. Das Hauptproblem zu diesem Zeitpunkt war das Debugging: In .NET war alles großartig, aber danach in die Welt des eingebetteten Lua einzutauchen, wenn man außer Logs kein Debugging hat, war ziemlich herausfordernd. Außerdem brach die Replikation aus unerklĂ€rlichen GrĂŒnden gelegentlich zusammen, weshalb wir uns intensiver mit der Funktionsweise der Tarantool-Engine befassen mussten. Der Chat half dabei, weniger die Dokumentation, manchmal schauten wir uns den Code an. Zu diesem Zeitpunkt war die Dokumentation eher mĂ€ĂŸig.

So dauerte es mehrere Monate, um Erfahrung zu sammeln und anstÀndige Ergebnisse bei der Arbeit mit Tarantool zu erzielen. Wir haben in Git Referenzimplementierungen erstellt, die bei der Entwicklung neuer Mikrodienste halfen. Zum Beispiel, wenn die Aufgabe auftauchte, einen weiteren Mikrodienst zu erstellen, schaute der Entwickler sich den Quellcode der Referenzlösung im Repository an, und die Erstellung eines neuen dauerte nicht mehr als eine Woche.

Das waren besondere Zeiten. Man konnte damals einfach zum Administrator am Nachbartisch gehen und sagen: „Gib mir eine VM.“ Nach etwa dreißig Minuten hatte man bereits die Maschine. Man hat sich selbst verbunden, alles installiert, und man bekam den Traffic dafĂŒr.

Heute funktioniert das so nicht mehr: Man muss das Monitoring fĂŒr den Service einrichten, Protokollierung vornehmen, die FunktionalitĂ€t mit Tests abdecken, eine VM oder eine Bereitstellung in K8s anfordern usw. Insgesamt wird es so besser sein, obwohl es lĂ€nger dauert und aufwendiger ist.

Teile und herrsche. Wie steht es um Lua?

Es gab ein ernstes Dilemma: Einige Teams hatten Schwierigkeiten, Änderungen in einem Service mit viel Logik in Lua zuverlĂ€ssig auszurollen. Oft endete dies in einer Nichtexistenz des Services.

Das heißt, die Entwickler bereiten eine Änderung vor. Tarantool beginnt mit der Migration, und die Replikation lĂ€uft noch mit altem Code; dort trifft ein DDL ein, noch etwas anderes, und der Code bricht einfach zusammen, weil das nicht berĂŒcksichtigt wird. Infolgedessen war das Update-Verfahren fĂŒr die Administratoren auf einem A4-Blatt niedergeschrieben: Replikation stoppen, dies aktualisieren, Replikation einschalten, hier ausschalten, dort aktualisieren. Ein Albtraum!

Letztendlich versuchen wir jetzt hĂ€ufig, in Lua nichts zu tun. Einfach ĂŒber iproto (das binĂ€re Protokoll zur Interaktion mit dem Server) und das war's. Vielleicht liegt es am Mangel an Wissen der Entwickler, aber aus dieser Sicht ist das System komplex.

Wir folgen diesem Szenario nicht immer blind. Heute gibt es bei uns kein Schwarz und Weiß: entweder alles in Lua oder alles in Go. Wir verstehen bereits, wie es kombiniert werden kann, um spĂ€ter keine Probleme mit der Migration zu bekommen.

Wo gibt es derzeit Tarantool?
Tarantool wird im Dienst zur Berechnung des endgĂŒltigen Preises von Waren unter BerĂŒcksichtigung von Rabattgutscheinen, auch bekannt als „Promotizer“, eingesetzt. Wie bereits erwĂ€hnt, zieht er sich derzeit zurĂŒck: Ein neuer Katalogdienst mit vorab berechneten Preisen ersetzt ihn. Aber vor einem halben Jahr wurden alle Berechnungen im „Promotizer“ durchgefĂŒhrt. FrĂŒher war die HĂ€lfte seiner Logik in Lua geschrieben. Vor zwei Jahren wurde der Dienst zu einem Speicher und die Logik in Go umgeschrieben, da die Mechanik der Rabatte sich etwas geĂ€ndert hat und der Dienst nicht genĂŒgend Leistung hatte.

Einer der kritischsten Dienste ist das Benutzerprofil. Das heißt, alle Benutzer von Wildberries werden in Tarantool gespeichert, und es sind etwa 50 Millionen. Ein nach Benutzer-ID shardiertes System, verteilt auf mehrere DCs mit einer Anbindung an Go-Dienste.
Bei RPS war frĂŒher der „Promotizer“ der FĂŒhrer, es kam bis zu 6.000 Anfragen. In einem bestimmten Moment hatten wir 50-60 Instanzen. Jetzt ist der FĂŒhrer bei RPS - die Benutzerprofile, etwa 12.000. In diesem Dienst wird ein kundenspezifisches Sharding mit einer Aufteilung nach Benutzer-ID-Bereichen angewendet. Der Dienst bedient mehr als 20 Maschinen, aber das ist zu viel; wir planen, die zugewiesenen Ressourcen zu reduzieren, da 4-5 Maschinen ausreichend Leistung bieten.

Der Dienst fĂŒr Sitzungen ist unser erster Dienst auf vshard und Cartridge. Die Konfiguration von vshard und das Update von Cartridge erforderten einige ArbeitsaufwĂ€nde von uns, aber am Ende hat alles geklappt.

Der Dienst zur Anzeige verschiedener Banner auf der Website und in der mobilen Anwendung war einer der ersten, die sofort auf Tarantool veröffentlicht wurden. Dieser Dienst ist bemerkenswert, da er etwa 6-7 Jahre alt ist, immer noch im Einsatz ist und nie neu gestartet wurde. Es wurde eine Master-Master-Replikation verwendet. Es gab nie Probleme.

Es gibt ein Beispiel fĂŒr die Nutzung von Tarantool fĂŒr die FunktionalitĂ€t schneller Nachschlagewerke im Lagerverwaltungssystem, um in bestimmten FĂ€llen Informationen schnell zu ĂŒberprĂŒfen. Wir haben versucht, dafĂŒr Redis zu verwenden, aber die Daten im Speicher nahmen mehr Platz ein als bei Tarantool.

Die Dienste fĂŒr Wartelisten, Kundenabonnements, die derzeit angesagten Stories und die zwischenzeitlich aufgegebenen Waren arbeiten ebenfalls mit Tarantool. Der letzte Dienst benötigt im Speicher etwa 120 GB. Das ist der umfangreichste Dienst aus den genannten GrĂŒnden.

Fazit

Dank sekundĂ€ren Indizes in Kombination mit Key-Value und TransaktionsfĂ€higkeit eignet sich Tarantool hervorragend fĂŒr architektonische Lösungen, die auf Mikrodiensten basieren. Allerdings hatten wir Schwierigkeiten, als wir Änderungen in Diensten mit viel Logik in Lua ausrollten – die Dienste fielen hĂ€ufig aus. Es gelang uns nicht, dieses Problem zu bewĂ€ltigen, und im Laufe der Zeit kamen wir zu verschiedenen Kombinationen von Lua und Go: Wir wissen, wo einer der beiden Sprachen zum Einsatz kommen sollte.

Was gibt es noch zu lesen

Quelle: habr.com

60GB SSD 8Gb DDR4