adesso Blog

Um eine Microservices-Architektur erfolgreich zu implementieren, müssen verschiedene Aspekte berücksichtigt werden. Dazu gehören unter anderem: Wie gehen wir mit Transaktionalität um? Wie soll das System reagieren, wenn mitten in einem verteilten Geschäftsprozess ein Fehler auftritt? In diesem Blog-Beitrag werden Lösungen für diese Probleme vorgestellt.

Transaktionalität in Microservicearchitekturen

Stellt euch vor, ihr wollt einen Kuchen backen. Ihr nehmt alle Zutaten, vermischt sie und schiebt den Teig in den Ofen. Dann stellt ihr fest, dass ihr den Zucker vergessen habt. Also nehmt ihr den Teig aus dem Ofen, gebt den Zucker dazu und schiebt ihn wieder hinein. Klingt einfach, oder? Aber was wäre, wenn ihr diesen Kuchen in einem Restaurant backen müsstest, in dem es zehn verschiedene Küchenstationen gibt, die jeweils von einem anderen Koch geleitet werden und jede Station einen Arbeitsschritt ausführen muss, um den Kuchen fertigzustellen? Und zu allem Überfluss spricht jeder Koch auch noch eine andere Sprache. Dann wird das Kuchenbacken zum Alptraum.

Diese Analogie beschreibt das Problem, mit dem eine Microservices-Architektur bei der Implementierung komplexer Geschäftsvorfälle konfrontiert werden kann. An der Stelle kommt das Saga-Modell ins Spiel.

Was ist das Saga-Muster?

Das Saga-Pattern ist ein Entwurfsmuster für die Implementierung komplexer Geschäftstransaktionen in Microservices-Architekturen. Es stellt sicher, dass die Datenkonsistenz über mehrere Microservices hinweg erhalten bleibt, indem eine große Transaktion in kleinere, überschaubare Schritte aufgeteilt wird. Das Muster wird “Saga” genannt, weil es ähnlich wie eine Geschichte oder eine Reise funktioniert, die in kleinere Segmente unterteilt ist, von denen jedes sein eigenes Ergebnis hat, das zum Gesamtergebnis der Reise beiträgt.

Wie funktioniert das Saga-Muster?

Bei einer Saga wird eine komplexe Transaktion in mehrere Schritte unterteilt. Diese werden jeweils in verschiedenen Teiltransaktionen innerhalb eines Dienstes ausgeführt. Am Ende jeder Transaktion wird ein Ereignis ausgelöst, das über den abgeschlossenen Prozess informiert und gleichzeitig den nächsten Schritt in der Saga bei einem anderen Service auslöst.

Beispiel einer Saga für einen Bestellvorgang

Beispiel einer Saga für einen Bestellvorgang

Im oben gezeigten Diagramm sehen wir am Beispiel einer E-Commerce-Bestellung, wie das Saga Pattern funktioniert:

Nach dem Eintreten des Triggers (Bestellung bestätigt) werden die Teiltransaktionen der Saga Schritt für Schritt innerhalb jedes Microservices ausgeführt. Nachdem jeder Service seine internen Operationen abgeschlossen hat, wird ein Ereignis ausgelöst, das den nächsten Schritt einleitet. Am Ende befindet sich das Gesamtsystem in einem neuen, konsistenten Zustand.

Im Falle eines Fehlers in der Mitte der Saga werden wiederum Ereignisse in umgekehrter Richtung ausgelöst, die sogenannte “kompensierende Transaktionen” auslösen sollen. Diese sorgen dafür, dass bei jedem beteiligten Dienst die zuvor durchgeführten Schritte rückgängig gemacht werden. So wird sichergestellt, dass die Datenkonsistenz über Microservices hinweg erhalten bleibt.

Beispiel einer Saga für einen Bestellvorgang mit kompensierenden Transaktionen

Beispiel einer Saga für einen Bestellvorgang mit kompensierenden Transaktionen

Arten von Sagas

Bei Sagas gibt es eine Hauptunterteilung in zwei verschiedenen Arten:

Choreografie

Choreographische Sagas basieren auf unserem oben genannten Beispiel: Die Microservices, die Teil einer Saga sind, interagieren und steuern selbstständig den gesamten Ablauf.

Eine Choreography Saga kann mit einem einfachen Kochabend mit Freunden verglichen werden. Die Anzahl der Beteiligten ist überschaubar und die Schritte zur Zubereitung der Zutaten sind einfach. Daher ist es nicht notwendig, dass eine bestimmte Person den gesamten Prozess steuert.

Bei der Choreographie kommunizieren die Microservices direkt miteinander, um die Teiltransaktionen auszuführen. Jeder Microservice kennt seine eigenen Aufgaben und den Kontext der Transaktion. Die Kommunikation erfolgt in der Regel asynchron über Events oder Messages. Jeder Microservice führt seine Aufgaben aus und löst die entsprechenden Events aus, um den nächsten Microservice in der Sequenz zu informieren. Dies setzt voraus, dass sich die einzelnen Microservices koordinieren können, um den Transaktionszustand aufrecht zu erhalten. Es gibt keinen zentralen Kontrollpunkt, der die Ausführung überwacht.

Diese Art von Saga ist in der Regel einfach zu implementieren und eignet sich gut für kurzlebige Transaktionen mit wenigen Schritten, bei denen kein Tracing erforderlich ist und keine Notwendigkeit besteht, den Transaktionsstatus zu verfolgen.

Andererseits wird es bei zu vielen beteiligten Diensten immer schwieriger, festzustellen, wo Fehler aufgetreten sind. Gleichzeitig wird die Anzahl der Laufzeitabhängigkeiten unübersichtlicher und schwieriger zu verwalten.

Für diese Herausforderung ist die andere Art von Saga geeignet:

Orchestrator

Bei der Saga-Orchestrierung gibt es einen zentralen Orchestrator, der die Ausführung der Teiltransaktionen steuert. Der Orchestrator ist für die Koordination der beteiligten Microservices und die Verwaltung des Transaktionsstatus verantwortlich. Er stellt sicher, dass die Schritte in der richtigen Reihenfolge ausgeführt werden und kann im Fehlerfall Kompensationsmaßnahmen einleiten, um den vorherigen Zustand wiederherzustellen. Der Orchestrator fungiert als zentrale Anlaufstelle für die Transaktionssteuerung und die Kommunikation zwischen den Microservices.

Beispiel einer Orchestrator-Saga für einen Bestellvorgang

Beispiel einer Orchestrator-Saga für einen Bestellvorgang

Im oberen Diagramm ist der bereits bekannte Bestellprozess dargestellt, diesmal jedoch als Orchestrator-Saga: Der Hauptunterschied besteht in der Verwendung eines dedizierten Services, der für die Orchestrierung, das Tracking und das Tracing der notwendigen Schritte verantwortlich ist.

Ein wichtiger Vorteil dieser Art von Saga ist, dass zyklische Abhängigkeiten vermieden werden, da die Services während der Transaktion nicht miteinander, sondern nur mit dem Orchestrator kommunizieren. Ein weiterer Vorteil ist die erhöhte Übersichtlichkeit, da sich die Definition des gesamten Workflows an einer Stelle befindet, wo sie angepasst und getestet werden kann.

Diese Vorteile werden jedoch mit hohen Kosten erkauft: Der Orchestrator wird zum Single Point of Failure, das heißt, wenn er nicht verfügbar oder fehlerhaft ist, kann die gesamte Transaktion nicht ausgeführt werden, egal wie zuverlässig die anderen beteiligten Dienste sind. Aufgrund der erhöhten Komplexität bei der Implementierung und Wartung eignet sich diese Art von Saga für Geschäftstransaktionen, die viele (typischerweise mehr als vier) beteiligte Services mit langwierigen Schritten beinhalten, deren Status verfolgt werden muss.

In unserem Küchenbeispiel ist der Orchestrator der Chefkoch, der die Küchenstationen im Restaurant koordiniert. Er gibt jedem Mitarbeitenden Anweisungen, welche Zutaten in der richtigen Reihenfolge zubereitet werden müssen. Wenn es bei einem Schritt zu Problemen kommt, sorgt er dafür, dass alle Beteiligten Massnahmen ergreifen, damit die Küche am Schluss in einem guten Zustand ist.

Fazit

Wir lernten das Saga-Modell und seine Hauptmerkmale kennen. Wir haben uns auch mit den wichtigsten Arten von Sagas beschäftigt: Choreographie und Orchestrierung. Beide haben ihre Vor- und Nachteile, die bei jeder Anwendung gegeneinander abgewogen werden müssen. Entscheidend für die Wahl sind die Anzahl und Dauer der Arbeitsschritte und der Bedarf an Statusverfolgung.

Wenn ihr also das nächste Mal einen Kuchen backt oder versucht, eine komplexe, verteilte Geschäftstransaktion in einer Mikroservicearchitektur abzuschließen, denkt an das Saga-Muster als geheime Zutat für den Erfolg!

Bild Eleazar Alejandro  Araujo

Autor Eleazar Alejandro Araujo

Eleazar arbeitet seit 2016 als Fullstack Engineer und beschäftigt sich gerne mit JVM-Sprachen und Architekturthemen.

Diese Seite speichern. Diese Seite entfernen.