Einführung
Wie Sie wissen, verursacht der Übergang von einem Monolithen zu einer Microservice-Architektur eine Reihe von Schwierigkeiten, die sowohl mit dem technischen Teil des Projekts als auch mit dem menschlichen Faktor verbunden sind. Eine der schwierigsten technischen Herausforderungen besteht darin, die Konsistenz in einem verteilten System sicherzustellen .
Konsistenz
Ein eher subtiler Punkt ist, dass sich die Konsistenz im Kontext verteilter Systeme von der Konsistenz im Kontext von Datenbanken unterscheidet. Unter Konsistenz verstehen wir außerdem genau das Erste: Eine unvollständige (fehlerhafte) Operation führt zu keinen Effekten und ändert die Daten nicht. Bei gleichzeitigem Zugriff auf Daten werden alle Operationen als atomar betrachtet (Sie können das Zwischenergebnis der Operation nicht sehen), wenn die Daten mehrere Kopien haben (Replikation). Dann ist die Reihenfolge der Anwenden von Vorgängen auf alle Kopien gleich. Das heißt, wir möchten tatsächlich eine ACID-Transaktion erhalten, aber nur eine verteilte.
Die Ursache des Problems
Warum ist es schwierig, die Konsistenz in einer Microservice-Architektur aufrechtzuerhalten? Tatsache ist, dass dieser Architekturstil häufig die Verwendung der Datenbank pro Dienstmuster beinhaltet. Ich möchte Sie daran erinnern, dass dieses Muster darin besteht, dass jeder Mikrodienst seine eigene unabhängige Basis oder Basen hat (Basen, da zusätzlich zur primären Datenquelle beispielsweise ein Cache verwendet werden kann). Dieser Ansatz ermöglicht es einerseits, keine impliziten Datenformatverknüpfungen zwischen Mikrodiensten hinzuzufügen (Mikrodienste interagieren nur explizit über die API), andererseits, um einen solchen Vorteil der Mikrodienstarchitektur als technologieunabhängig zu nutzen (wir können die Datenspeichertechnologie auswählen, die für die bestimmte Belastung des Mikrodienstes geeignet ist ). Mit all dem haben wir jedoch die Garantie der Datenkonsistenz verloren. Urteile selbstDer Monolith kommunizierte mit einer großen Datenbank, die die Bereitstellung von ACID-Transaktionen ermöglichte. Jetzt gibt es viele Datenbanken, und anstelle einer großen ACID-Transaktion haben wir viele kleine ACID-Transaktionen. Unsere Aufgabe wird es sein, alle diese Transaktionen in einer zu kombinierenverteilt .
Optimistische Konsistenz
Das erste, was mir in den Sinn kommt, ist das Konzept der optimistischen Konsistenz: Wir legen so viele Transaktionen fest, wie wir möchten, für so viele Speicher-Engines wie nötig. Gleichzeitig erwarten wir, dass alles gut wird, und wenn alles schlecht ist, dann sagen wir, dass am Ende alles gut wird. Wenn am Ende alles schlecht ist, sagen wir: "Ja, das passiert, aber mit extrem geringer Wahrscheinlichkeit."
Scherz beiseite, die Vernachlässigung der Konsistenz, wenn sie nicht geschäftskritisch ist, ist eine gute Idee, besonders wenn man bedenkt, wie viel Aufwand uns die Wartung kostet (was Sie hoffentlich etwas später sehen werden).
Konsistenzoptionen
Wenn Konsistenz für das Unternehmen von entscheidender Bedeutung ist, gibt es verschiedene Möglichkeiten, dies zu erreichen. Wenn es sich um eine Situation handelt, in der Daten von einem Dienst aktualisiert werden (z. B. findet eine Datenbankreplikation statt), können Standardkonsistenzalgorithmen wie Paxos oder Raft angewendet werden. Solche Transaktionen werden als homogen bezeichnet . Wenn die Daten von mehreren Diensten aktualisiert werden ( dh eine heterogene Transaktion findet statt ), wie beginnt dann die Komplexität, über die wir oben gesprochen haben.
Einerseits können wir immer noch die Notwendigkeit umgehen, eine verteilte Transaktion bereitzustellen, indem wir eine service-basierte Architektur anstreben (wir kombinieren Services so, dass die Transaktion homogen ist). Eine solche Lösung ist unter dem Gesichtspunkt der Prinzipien der Microservice-Architektur nicht sehr kanonisch, aber technisch viel einfacher, weshalb sie in der Praxis häufig verwendet wird. Auf der anderen Seite können wir die kanonischen Mikrodienste verlassen, aber gleichzeitig einen der Mechanismen anwenden, um verteilte Transaktionen sicherzustellen: ein zweiphasiges Commit oder eine Saga. In diesem Artikel wird die erste Option untersucht und die zweite beim nächsten Mal erläutert.
Zwei-Phasen-Commit
Der Mechanismus ist äußerst einfach: Es gibt einen Transaktionsmanager, der die Transaktion tatsächlich koordiniert. In der ersten Phase (Vorbereitung) gibt der Transaktionsmanager den entsprechenden Befehl für Ressourcenmanager aus, nach dem sie Daten in ihre Protokolle schreiben, die festgeschrieben werden sollen. Nachdem alle Ressourcenmanager eine Bestätigung über den erfolgreichen Abschluss der ersten Stufe erhalten haben, startet der Transaktionsmanager die zweite Stufe und gibt den nächsten Befehl (Commit) aus, nach dem die Ressourcenmanager die zuvor akzeptierten Änderungen anwenden.
Trotz seiner offensichtlichen Einfachheit weist dieser Ansatz eine Reihe von Nachteilen auf. Erstens muss die gesamte Transaktion zurückgesetzt werden, wenn mindestens ein Ressourcenmanager in der zweiten Phase ausfällt. Somit wird eines der Prinzipien der Microservice-Architektur verletzt - die Widerstandsfähigkeit gegen Fehler (als wir zu einem verteilten System kamen, gingen wir sofort davon aus, dass ein Fehler darin die Norm und keine Ausnahmesituation ist). Wenn es viele Fehler gibt (und es wird viele davon geben), muss der Vorgang des Abbrechens von Transaktionen automatisiert werden (einschließlich des Schreibens von Transaktionen, die Transaktionen zurücksetzen). Zweitens ist der Transaktionsmanager selbst ein einzelner Fehlerpunkt. Er sollte in der Lage sein, Transaktionen transaktionsmäßig mit Id-Shniks zu versehen. Drittens ist es logisch anzunehmen, dass das Repository dazu in der Lage sein sollte, da dem Repository spezielle Befehle gegeben werden.Das heißt, Sie müssen den XA-Standard einhalten, und nicht alle modernen Technologien erfüllen ihn (Broker wie Kafka, RabbitMQ und NoSQL-Lösungen wie MongoDB und Cassandra unterstützen keine zweiphasigen Commits).
Die Schlussfolgerung, die sich aus all diesen Faktoren ergibt, wurde von Chris Richardson perfekt formuliert: "2PC keine Option" (Zwei-Phasen-Commit ist keine Option).
Ausgabe
Wir haben herausgefunden, warum verteilte Transaktionen das wichtigste technische Problem einer Microservice-Architektur sind, und haben über verschiedene Optionen zur Lösung dieses Problems gesprochen und den Zwei-Phasen-Festschreibungsmechanismus ausführlich erörtert.
Ich lade alle ein , sich für mein Webinar über den Kurs anzumelden , in dem ich Sie ausführlich über das Schulungsformat informieren und alle in das Schulungsprogramm einführen werde.