Das Buch "Microservices. Entwicklungs- und Refactoring-Muster »

Bild Hallo habrozhiteli! Wenn Sie lange Zeit den Eindruck haben, dass sich die gesamte Entwicklung und Bereitstellung in Ihrem Unternehmen bis zum Äußersten verlangsamt hat, gehen Sie zur Microservice-Architektur. Es bietet die kontinuierliche Entwicklung, Bereitstellung und Bereitstellung von Anwendungen jeder Komplexität.

Das Buch richtet sich an Entwickler und Architekten großer Unternehmen und erklärt, wie Anwendungen im Geiste der Microservice-Architektur entworfen und geschrieben werden. Außerdem wird beschrieben, wie eine große Anwendung umgestaltet wird - und der Monolith wird zu einer Reihe von Mikrodiensten.

Wir bieten Ihnen an, sich mit der Passage "Transaktionsmanagement in der Microservice-Architektur" vertraut zu machen.

Fast jede Anforderung, die von einer Industrieanwendung verarbeitet wird, wird im Rahmen einer Datenbanktransaktion ausgeführt. Entwickler solcher Anwendungen verwenden Frameworks und Bibliotheken, die die Arbeit mit Transaktionen vereinfachen. Einige Tools bieten eine wichtige API zum manuellen Starten, Festschreiben und Zurücksetzen von Transaktionen. Und Frameworks wie Spring haben einen deklarativen Mechanismus. Spring unterstützt die Annotation @Transactional, die automatisch eine Methode innerhalb einer Transaktion aufruft. Dank dessen wird das Schreiben von Transaktionsgeschäftslogik ganz einfach.

Genauer gesagt ist die Verwaltung von Transaktionen in monolithischen Anwendungen, die auf eine einzelne Datenbank zugreifen, einfach. Wenn die Anwendung mehrere Datenbanken und Nachrichtenbroker verwendet, wird dieser Prozess schwieriger. Nun, in der Microservice-Architektur decken Transaktionen mehrere Services ab, von denen jeder eine eigene Datenbank hat. Unter solchen Umständen sollte die Anwendung einen komplexeren Transaktionsmechanismus verwenden. Wie Sie gleich sehen werden, ist der traditionelle Ansatz für verteilte Transaktionen in modernen Anwendungen nicht praktikabel. Microservice-basierte Systeme sollten stattdessen Storytelling verwenden.

Bevor wir jedoch zu den Narrativen übergehen, wollen wir uns ansehen, warum das Transaktionsmanagement so viele Komplexitäten in der Microservice-Architektur verursacht.

4.1.1. Microservice-Architektur und die Notwendigkeit verteilter Transaktionen


Stellen Sie sich vor, Sie sind Entwickler bei FTGO und für die Implementierung des Systembetriebs createOrder () verantwortlich. Wie in Kapitel 2 beschrieben, muss dieser Vorgang sicherstellen, dass der Kunde Bestellungen aufgeben, Bestelldetails überprüfen, die Bankkarte des Kunden autorisieren und einen Bestelldatensatz in der Datenbank erstellen kann. Die Implementierung dieser Aktionen wäre in einer monolithischen Anwendung relativ einfach. Alle zur Überprüfung der Bestellung erforderlichen Daten sind bereit und verfügbar. Darüber hinaus könnten ACID-Transaktionen verwendet werden, um die Datenkonsistenz sicherzustellen. Sie können einfach die Annotation @Transactional für die Dienstmethode createOrder () angeben.

Das Ausführen dieser Operation in einer Microservice-Architektur ist jedoch viel schwieriger. Wie in Abb. 4.1 werden die für createOrder () -Operationen erforderlichen Daten auf mehrere Dienste verteilt. createOrder () liest Informationen aus dem Verbraucherdienst und aktualisiert den Inhalt der Bestell-, Küchen- und Buchhaltungsdienste.

Da jeder Dienst über eine eigene Datenbank verfügt, sollten Sie einen Mechanismus verwenden, um Daten zwischen ihnen zu koordinieren.

4.1.2. Probleme mit verteilten Transaktionen


Der traditionelle Ansatz zur Gewährleistung der Datenkonsistenz zwischen mehreren Diensten, Datenbanken oder Nachrichtenbrokern ist die Verwendung verteilter Transaktionen. Der De-facto-Standard für das verteilte Transaktionsmanagement ist X / Open XA (siehe en.wikipedia.org/wiki/XA ). Das XA-Modell verwendet Two-Phase-Commit (2PC), um sicherzustellen, dass alle Änderungen an der Transaktion gespeichert oder zurückgesetzt werden. Dies erfordert, dass Datenbanken, Nachrichtenbroker, Datenbanktreiber und Messaging-APIs dem XA-Standard entsprechen. Außerdem ist ein Interprozesskommunikationsmechanismus erforderlich, der globale XA-Transaktionskennungen verteilt. Die meisten relationalen Datenbanken sind XA-kompatibel, ebenso wie einige Nachrichtenbroker. Beispielsweise kann eine Java EE-basierte Anwendung verteilte Transaktionen mithilfe des JTA ausführen.

Bild

Trotz ihrer Einfachheit weisen verteilte Transaktionen eine Reihe von Problemen auf. Viele moderne Technologien, einschließlich NoSQL-Datenbanken wie MongoDB und Cassandra, unterstützen sie nicht. Verteilte Transaktionen werden von einigen modernen Nachrichtenbrokern wie RabbitMQ und Apache Kafka nicht unterstützt. Wenn Sie sich also für verteilte Transaktionen entscheiden, stehen Ihnen viele moderne Tools nicht zur Verfügung.

Ein weiteres Problem bei verteilten Transaktionen besteht darin, dass es sich um eine Form des synchronen IPC handelt, der die Verfügbarkeit beeinträchtigt. Damit eine verteilte Transaktion festgeschrieben werden kann, müssen alle daran beteiligten Dienste zugänglich sein. Wie in Kapitel 3 beschrieben, ist die Systemzugänglichkeit ein Produkt der Zugänglichkeit aller Transaktionsteilnehmer. Wenn zwei Dienste mit einer Verfügbarkeit von 99,5% an einer verteilten Transaktion teilnehmen, beträgt die Gesamtverfügbarkeit 99%, was viel weniger ist. Jeder zusätzliche Service senkt den Verfügbarkeitsgrad. Eric Brewer formulierte den CAP-Satz, der besagt, dass ein System nur zwei der folgenden drei Eigenschaften haben kann: Konsistenz, Zugänglichkeit und Partitionswiderstand (en.wikipedia.org/wiki/CAP_ Theorem). Heute bevorzugen Architekten erschwingliche Systeme, die auf Konsistenz verzichten.

Verteilte Transaktionen mögen auf den ersten Blick attraktiv erscheinen. Aus Sicht des Entwicklers haben sie das gleiche Softwaremodell wie lokale Transaktionen. Aufgrund der zuvor beschriebenen Probleme ist diese Technologie in modernen Anwendungen nicht realisierbar. Kapitel 3 zeigte, wie Sie Nachrichten als Teil einer Datenbanktransaktion senden, ohne verteilte Transaktionen zu verwenden. Um das komplexere Problem der Gewährleistung der Datenkonsistenz in einer Microservice-Architektur zu lösen, muss die Anwendung einen anderen Mechanismus verwenden, der auf dem Konzept lose gekoppelter asynchroner Dienste basiert. Und hier sind die Erzählungen nützlich.

4.1.3. Verwenden Sie die Storytelling-Vorlage, um die Datenkonsistenz zu gewährleisten


Storytelling ist ein Mechanismus, der die Datenkonsistenz in einer Microservice-Architektur ohne die Verwendung verteilter Transaktionen sicherstellt. Die Erzählung wird für jedes Systemteam erstellt, das Daten in mehreren Diensten aktualisieren muss. Dies ist eine Folge lokaler Transaktionen, von denen jede Daten in einem Dienst aktualisiert, wobei die bekannten Frameworks und Bibliotheken für ACID-Transaktionen verwendet werden, die zuvor erwähnt wurden.

Vorlage zum Geschichtenerzählen

Gewährleistet die Datenkonsistenz zwischen Diensten mithilfe einer Folge lokaler Transaktionen, die mithilfe asynchroner Nachrichten koordiniert werden. Siehe microservices.io/patterns/data/saga.html .

Die Systemoperation leitet die erste Stufe der Erzählung ein. Der Abschluss einer lokalen Transaktion führt zu Folgendem. In Abschnitt 4.2 sehen Sie, wie die Koordination dieser Schritte mithilfe asynchroner Nachrichten erreicht wird. Ein wichtiger Vorteil von asynchronem Messaging besteht darin, dass sichergestellt wird, dass alle Phasen der Erzählung abgeschlossen sind, auch wenn auf einen oder mehrere Teilnehmer nicht zugegriffen werden kann.

Erzählungen unterscheiden sich in einigen wichtigen Punkten von ACID-Transaktionen. Erstens fehlt ihnen die Isolation (mehr dazu in Abschnitt 4.3). Da jede lokale Transaktion ihre Änderungen erfasst, müssen Sie zum Zurücksetzen der Story außerdem Ausgleichstransaktionen verwenden, die später in diesem Abschnitt erläutert werden. Betrachten Sie ein Beispiel für das Erzählen von Geschichten.

Narratives Beispiel: Erstellen einer Bestellung


In diesem Kapitel verwenden wir als Beispiel die Erzählung "Bestellung erstellen" (Abb. 4.2). Es implementiert die Operation createOrder (). Die erste lokale Transaktion wird durch eine externe Auftragserstellungsanforderung ausgelöst. Die restlichen fünf Transaktionen werden nacheinander ausgelöst.

Bild

Diese Erzählung besteht aus den folgenden lokalen Transaktionen.

1. Bestellservice. Erstellt eine Bestellung mit dem Status APPROVAL_PENDING.

2. Service Consumer. Überprüft, ob der Kunde Bestellungen aufgeben kann.

3. Küchenservice. Überprüft die Details der Bestellung und erstellt eine Anfrage mit dem Status CREATE_PENDING.

4. Buchhaltungsservice. Autorisiert die Bankkarte eines Kunden.

5. Küchenservice. Ändert den Status einer Anwendung in AWAITING_ACCEPTANCE.

6. Serviceauftrag. Ändert den Bestellstatus in GENEHMIGT.

In Abschnitt 4.2 werde ich zeigen, wie die an der Story beteiligten Dienste mithilfe asynchroner Nachrichten miteinander interagieren. Der Dienst veröffentlicht eine Nachricht nach Abschluss einer lokalen Transaktion. Dies leitet die nächste Stufe der Erzählung ein und ermöglicht nicht nur einen schwachen Zusammenhalt der Teilnehmer, sondern auch die vollständige Umsetzung der Erzählung. Selbst wenn der Empfänger vorübergehend nicht verfügbar ist, puffert der Broker die Nachricht, bis sie zugestellt werden kann.

Die Erzählungen scheinen einfach zu sein, aber ihre Verwendung ist mit einigen Schwierigkeiten verbunden, insbesondere mit einem Mangel an Isolation zwischen ihnen. Die Lösung des Problems ist in Abschnitt 4.3 beschrieben. Ein weiterer nicht trivialer Aspekt ist das Zurücksetzen von Änderungen, wenn ein Fehler auftritt. Mal sehen, wie das gemacht wird.

Narrative verwenden Gegentransaktionen, um Änderungen rückgängig zu machen


Herkömmliche ACID-Transaktionen haben eine großartige Funktion: Geschäftslogik kann eine Transaktion leicht zurücksetzen, wenn ein Verstoß gegen Geschäftsregeln festgestellt wird. Es führt einfach den Befehl ROLLBACK aus und die Datenbank bricht alle bisher vorgenommenen Änderungen ab. Leider kann die Story nicht automatisch zurückgesetzt werden, da in jeder Phase die Änderungen in der lokalen Datenbank erfasst werden. Dies bedeutet beispielsweise, dass die FTGO-Anwendung im Falle einer fehlgeschlagenen Autorisierung einer Bankkarte in der vierten Stufe der Erzählung "Bestellung erstellen" die in den vorherigen drei Stufen vorgenommenen Änderungen manuell stornieren muss. Sie müssen die sogenannten Offset-Transaktionen schreiben.

Angenommen, die (n + 1) -te Transaktion in der Story ist fehlgeschlagen. Es ist notwendig, die Konsequenzen der vorherigen n Transaktionen zu neutralisieren. Auf konzeptioneller Ebene hat jede dieser Ti-Stufen ihre eigene Kompensationstransaktion Ci, die die Wirkung von Ti aufhebt. Um den Effekt der ersten n Stufen zu kompensieren, muss die Erzählung jede Transaktion Ci in umgekehrter Reihenfolge ausführen. Die Sequenz sieht folgendermaßen aus: T1 ... Tn, Cn ... C1 (Abb. 4.3). In diesem Beispiel schlägt Schritt Tn + 1 fehl, was das Abbrechen der Schritte T1 ... Tn erfordert.

Bild

Die Erzählung führt Ausgleichstransaktionen in umgekehrter Reihenfolge zu den ursprünglichen aus: Cn ... C1. Hier arbeitet der gleiche sequentielle Ausführungsmechanismus wie im Fall von Ti. Die Beendigung von Ci sollte Ci - 1 initiieren.

Nehmen Sie zum Beispiel die Erzählung von Order erstellen. Es kann aus verschiedenen Gründen fehlschlagen.

1. Falsche Informationen über den Kunden oder der Kunde darf keine Bestellungen erstellen.

2. Falsche Informationen über das Restaurant oder das Restaurant kann die Bestellung nicht annehmen.

3. Unfähigkeit, die Bankkarte eines Kunden zu autorisieren.

Im Falle eines Fehlers in der lokalen Transaktion muss der Koordinierungsmechanismus für das Geschichtenerzählen Ausgleichsschritte ausführen, die die Bestellung und möglicherweise die Bestellung ablehnen. In der Tabelle. 4.1 Ausgleichstransaktionen werden für jede Phase der Erzählung "Auftrag erstellen" erfasst. Es ist zu beachten, dass nicht jede Phase eine Ausgleichstransaktion erfordert. Dies gilt beispielsweise für Lesevorgänge wie verifyConsumerDetails () oder für den Vorgang authorizeCreditCard (). Alle Schritte sind danach immer erfolgreich.

Bild

In Abschnitt 4.3 erfahren Sie, dass die ersten drei Phasen der Erzählung "Auftrag erstellen" als Transaktionen bezeichnet werden, die zur Kompensation verfügbar sind, da die folgenden Schritte möglicherweise fehlschlagen. Der vierte Schritt wird als Turning-Transaktion bezeichnet, da die nächsten Schritte niemals fehlschlagen. Die letzten beiden Schritte werden als wiederholbare Transaktionen bezeichnet, da sie immer erfolgreich enden.

Stellen Sie sich eine Situation vor, in der die Autorisierung der Bankkarte eines Kunden fehlschlägt, um zu verstehen, wie Ausgleichstransaktionen verwendet werden. In diesem Fall führt die Erzählung die folgenden lokalen Transaktionen aus.

1. Bestellservice. Erstellt eine Bestellung mit dem Status APPROVAL_PENDING.

2. Service Consumer. Überprüft, ob der Kunde Bestellungen aufgeben kann.

3. Küchenservice. Überprüft die Details der Bestellung und erstellt eine Anfrage mit dem Status CREATE_PENDING.

4. Buchhaltungsservice. Es wird erfolglos versucht, die Bankkarte eines Kunden zu autorisieren.

5. Küchenservice. Ändert den Status der Anwendung in CREATE_REJECTED.

6. Serviceauftrag. Ändert den Bestellstatus in ABGEWIESEN.

Die fünfte und sechste Stufe kompensieren Transaktionen, die die von den Küchendiensten vorgenommenen Aktualisierungen stornieren und dementsprechend bestellen. Die koordinierende narrative Logik ist für die Abfolge von direkten und gegenläufigen Transaktionen verantwortlich. Mal sehen, wie es funktioniert.

Über den Autor


Chris Richardson ist Entwickler, Architekt und Autor von POJOs in Action (Manning, 2006), in dem beschrieben wird, wie Java-Anwendungen auf Unternehmensebene mithilfe der Frameworks Spring und Hibernate erstellt werden. Er trägt die Ehrentitel von Java Champion und JavaOne Rock Star.

Chris entwickelte die Originalversion von CloudFoundry.com, einer frühen Implementierung der Java PaaS-Plattform für Amazon EC2.

Jetzt gilt er als anerkannter ideologischer Führer in der Welt der Mikrodienste und spricht regelmäßig auf internationalen Konferenzen. Chris hat microservices.io erstellt, das Microservice-Designmuster enthält. Darüber hinaus führt er weltweit Konsultationen und Schulungen für Organisationen durch, die auf Microservice-Architektur umsteigen. Chris arbeitet derzeit an seinem dritten Startup, Eventuate.io. Es ist eine Softwareplattform für die Entwicklung von Transaktions-Mikrodiensten.

»Weitere Informationen zum Buch finden Sie auf der Website des Herausgebers
» Inhalt
» Auszug

25% Rabatt auf Gutschein für Händler - Microservice Patterns
Nach Bezahlung der Papierversion des Buches wird ein elektronisches Buch per E-Mail verschickt.

Source: https://habr.com/ru/post/de462519/


All Articles