Das Entwurfsmuster Saga ist eine Möglichkeit zum Verwalten der Datenkonsistenz für Microservices in Szenarien mit verteilten Transaktionen. Das Saga-Muster umfasst eine Sequenz von Transaktionen, die alle Dienste aktualisieren und eine Meldung oder ein Ereignis veröffentlichen, um den nächsten Transaktionsschritt auszulösen. Wenn ein Schritt fehlschlägt, werden kompensierende Transaktionen ausgeführt, die den vorhergehenden Transaktionen entgegenwirken.
Kontext und Problem
Eine Transaktion ist eine einzelne Logik- oder Arbeitseinheit, die manchmal aus mehreren Vorgängen besteht. Innerhalb einer Transaktion beschreibt ein Ereignis eine Zustandsänderung, die bei einer Entität auftritt, und ein Befehl kapselt alle erforderlichen Informationen zum Durchführen einer Aktion oder zum Auslösen eines späteren Ereignisses.
Alle Transaktionen müssen unteilbar, konsistent, isoliert und von Dauer (atomic, consistent, isolated, durable: ACID) sein. Transaktionen innerhalb eines einzelnen Diensts sind ACID, jedoch erfordert die dienstübergreifende Datenkonsistenz eine dienstübergreifende Transaktionsverwaltungsstrategie.
In Architekturen mit mehreren Diensten:
- beschreibt die Unteilbarkeit eine unteilbare und nicht reduzierbare Gruppe von Vorgängen, die alle durchgeführt werden müssen, oder es werden keine ausgeführt.
- bedeutet die Konsistenz, dass die Transaktion die Daten nur von einem gültigen Zustand zu einem anderen gültigen Zustand bringt.
- garantiert die Isolation, dass gleichzeitige Transaktionen denselben Datenzustand erzeugen, der von nacheinander ausgeführten Transaktionen erzeugt werden würde.
- stellt die Dauerhaftigkeit sicher, dass Transaktionen auch bei einem Systemausfall oder Stromausfall committet bleiben.
Ein Datenbank-per-Microservice-Modell bietet viele Vorteile für Microservicearchitekturen. Indem Domänendaten gekapselt werden, kann jeder Dienst die am besten geeigneten Datenspeichertypen und -schemas nutzen, den eigenen Datenspeicher nach Bedarf skalieren und ist vor Fehlern in anderen Diensten geschützt. Allerdings gibt es einige Herausforderungen beim Sicherstellen der Datenkonsistenz über dienstspezifische Datenbanken hinweg.
Verteilte Transaktionen wie das Zweiphasencommit-Protokoll (2PC) erfordern, dass alle Teilnehmer in einer Transaktion einen Commit oder Rollback ausführen, bevor die Transaktion fortgesetzt werden kann. Allerdings unterstützen einige Teilnehmerimplementierungen wie NoSQL-Datenbanken und Nachrichtenbroker dieses Modell nicht.
Eine weitere Einschränkung bei verteilten Transaktionen ist die Synchronität und Verfügbarkeit der prozessübergreifenden Kommunikation. Die vom Betriebssystem bereitgestellte prozessübergreifende Kommunikation ermöglicht separaten Prozessen das Freigeben von Daten. Damit verteilte Transaktionen committet werden können, müssen alle teilnehmenden Dienste verfügbar sein, wodurch möglicherweise die Verfügbarkeit des Gesamtsystems reduziert wird. Für Architekturimplementierungen mit der prozessübergreifenden Kommunikation oder mit Transaktionseinschränkungen empfiehlt sich das Saga-Muster.
Lösung
Das Saga-Muster stellt Transaktionsverwaltung mithilfe einer Sequenz aus lokalen Transaktionen bereit. Eine lokale Transaktion beschreibt den unteilbaren Arbeitsaufwand, der von einem Saga-Teilnehmer durchgeführt wird. Jede lokale Transaktion aktualisiert die Datenbank und veröffentlicht eine Nachricht oder ein Ereignis, um die nächste lokale Transaktion in der Saga auszulösen. Wenn eine lokale Transaktion fehlschlägt führt das Saga-Muster eine Reihe kompensierender Transaktionen aus, die die Änderungen der vorhergehenden lokalen Transaktionen rückgängig machen.
In Saga-Mustern gilt:
- Kompensierbare Transaktionen sind Transaktionen, die möglicherweise rückgängig gemacht werden können, indem eine weitere Transaktion mit dem gegenteiligen Effekt verarbeitet wird.
- Pivot-Transaktionen sind der Go-/No-Go-Punkt in einer Saga. Wenn die Pivot-Transaktion committet wird, wird das Saga-Muster bis zum Abschluss ausgeführt. Bei einer Pivot-Transaktion kann es ich um eine Transaktion handeln, die weder kompensiert noch wiederholt werden kann, oder es handelt sich um die letzte kompensierbare Transaktion oder die erste wiederholbare Transaktion in der Saga.
- Wiederholbare Transaktionen sind Transaktionen, die auf die Pivot-Transaktion folgen und garantiert erfolgreich sind.
Es gibt zwei gängige Ansätze für die Saga-Implementierung: Choreographie und Orchestrierung. Jeder Ansatz umfasst seine eigenen Herausforderungen und Technologien zum Koordinieren des Workflows.
Choreographie
Die Choreographie ist eine Möglichkeit zum Koordinieren der Sagas, bei der Teilnehmer Ereignisse ohne einen zentralisierten Steuerungspunkt austauschen. Bei der Choreographie veröffentlicht jede lokale Transaktion Domänenereignisse, die lokale Transaktionen in anderen Diensten auslösen.
Vorteile
- Dieser Ansatz eignet sich für einfache Workflows, die wenige Teilnehmer erfordern und keine Koordinierungslogik benötigen.
- Es ist keine zusätzliche Dienstimplementierung und -wartung erforderlich.
- Es wird kein SPOF (Single Point of Failure) eingeführt, da die Aufgaben auf die Saga-Teilnehmer verteilt werden.
Nachteile
- Der Workflow kann beim Hinzufügen neuer Schritte verwirrend sein, da es schwierig ist, nachzuverfolgen, welche Saga-Teilnehmer auf welche Befehle lauschen.
- Es besteht das Risiko einer zyklischen Abhängigkeit zwischen Saga-Teilnehmern, da sie ihre Befehle gegenseitig verarbeiten.
- Integrationstests sind schwierig, weil alle Dienste zum Simulieren einer Transaktion ausgeführt werden müssen.
Orchestrierung
Die Orchestrierung ist eine Möglichkeit zum Koordinieren von Saga-Mustern, bei der eine zentralisierte Steuerung die Saga-Teilnehmer anweist, welche lokalen Transaktionen ausgeführt werden müssen. Der Saga-Orchestrator verarbeitet alle Transaktionen und weist die Teilnehmer anhand der Ereignisse an, welcher Vorgang durchgeführt werden soll. Der Orchestrator führt Saga-Anforderungen aus, speichert und interpretiert die Zustände aller Tasks und verarbeitet die Wiederherstellung nach Fehlern mit kompensierenden Transaktionen.
Vorteile
- Die Orchestrierung eignet sich für komplexe Workflows mit vielen Teilnehmer oder neuen Teilnehmern, die über Zeit hinzugefügt werden.
- Sie empfiehlt sich außerdem, wenn eine Kontrolle über alle Teilnehmer im Prozess und den Ablauf der Aktivitäten vorliegt.
- Es werden keine zyklischen Abhängigkeiten eingeführt, weil der Orchestrator einseitig von den Saga-Teilnehmern abhängig ist.
- Saga-Teilnehmer müssen die Befehle anderer Teilnehmer nicht kennen. Die klare Trennung von Anliegen vereinfacht die Geschäftslogik.
Nachteile
- Aufgrund der erhöhten Entwurfskomplexität ist die Implementierung einer Koordinierungslogik erforderlich.
- Es gibt einen zusätzlichen Fehlerpunkt, da der Orchestrator den gesamten Workflow verwaltet.
Probleme und Überlegungen
Beachten Sie bei der Implementierung des Saga-Musters die folgenden Punkte:
- Das Saga-Muster kann anfänglich eine Herausforderung darstellen, da es eine neue Denkweise zum Koordinieren einer Transaktion und zum Verwalten der Datenkonsistenz für einen Geschäftsprozess erfordert, der mehrere Microservices umfasst.
- Es ist besonders schwierig, das Saga-Muster zu debuggen, und die Komplexität steigt mit höherer Teilnehmerzahl.
- Für die Daten kann kein Rollback ausgeführt werden, da Saga-Teilnehmer Änderungen in ihren lokalen Datenbanken committen.
- Die Implementierung muss dazu fähig sein, eine Reihe potenzieller vorübergehender Fehler zu verarbeiten, Idempotenz zum Reduzieren von Nebeneffekten zu bieten und die Datenkonsistenz sicherzustellen. Die Idempotenz beschreibt, dass derselbe Vorgang mehrmals wiederholt werden kann, ohne dass das anfängliche Ergebnis geändert wird. Weitere Informationen finden Sie in diesem Leitfaden zur Sicherstellung von Idempotenz beim Verarbeiten von Nachrichten und beim gemeinsamen Aktualisieren des Zustands.
- Es empfiehlt sich, Einblicke zum Überwachen und Nachverfolgen des Saga-Workflows zu implementieren.
- Ein Mangel an Isolation der Teilnehmerdaten führt zu Problemen mit der Dauerhaftigkeit. Die Saga-Implementierung muss Gegenmaßnahmen enthalten, um Anomalien zu reduzieren.
- Ausgleichstransaktionen funktionieren nicht immer.
Wenn die entsprechenden Maßnahmen nicht ergriffen werden, können folgende Anomalien auftreten:
- Verlorene Updates, wenn eine Saga schreibt, ohne die Änderungen einer anderen Saga zu lesen
- Dirty Reads, wenn eine Transaktion oder Saga Updates liest, die von einer Saga vorgenommen wurden, die diese Updates noch nicht abgeschlossen hat
- Ungenaue/nicht wiederholbare Lesevorgänge, wenn verschiedene Saga-Schritte verschiedene Daten lesen, weil ein Datenupdate zwischen den Lesevorgängen auftritt
Folgende Gegenmaßnahmen werden empfohlen, um Anomalien zu reduzieren oder zu verhindern:
- Semantische Sperren: Dabei handelt es sich um eine Sperre auf Anwendungsebene, bei der eine kompensierbare Saga-Transaktion einen Semaphor verwendet, um anzugeben, dass ein Update ausgeführt wird.
- Kommutative Updates: Diese Updates können in einer beliebigen Reihenfolge ausgeführt werden und führen zum selben Ergebnis.
- Pessimistische Ansicht: Eine Saga kann Dirty Reads für Daten durchführen, während eine andere Saga eine kompensierbare Transaktion zum Durchführen eines Rollbacks für den Vorgang ausführt. Die pessimistische Ansicht ordnet das Saga-Muster neu an, damit zugrunde liegende Datenaktualisierungen in einer wiederholbaren Transaktion durchgeführt werden, wodurch die Wahrscheinlichkeit von Dirty Reads entfällt.
- Erneutes Lesen von Werten: Hiermit wird überprüft, ob die Daten unverändert sind. Dann wird der Datensatz aktualisiert. Wenn der Datensatz Änderungen aufweist, werden die Schritte abgebrochen und das Saga-Muster kann neu gestartet werden.
- Eine Versionsdatei zeichnet die Vorgänge in einem Datensatz auf, sobald diese eingehen, und führt diese in der richtigen Reihenfolge aus.
- Nach Wert: Bei dieser Gegenmaßnahme wird das Geschäftsrisiko der einzelnen Anforderungen verwendet, um den Parallelitätsmechanismus dynamisch auszuwählen. Anforderungen mit geringem Risiko bevorzugen Saga-Muster, während Anforderungen mit hohem Risiko verteilte Transaktionen bevorzugen.
Verwendung dieses Musters
Verwenden Sie das Saga-Muster in folgenden Fällen:
- Zum Sicherstellen der Datenkonsistenz in einem verteilten System ohne enge Kopplung
- Zum Durchführen eines Rollbacks oder zur Kompensierung, wenn einer der Vorgänge in der Sequenz fehlschlägt
Das Saga-Muster eignet sich in folgenden Fällen nicht:
- Bei eng gekoppelten Transaktionen
- Bei kompensierenden Transaktionen, die bei früheren Teilnehmern auftreten
- Bei zyklischen Abhängigkeiten
Beispiel
Eine Referenzimplementierung des Saga-Musters mit dem Orchestrierungsansatz, bei der ein Geldtransferszenario mit erfolgreichen und fehlgeschlagenen Workflows simuliert wird, finden Sie unter Orchestrierungsbasiertes Saga-Muster ohne Server.
Nächste Schritte
- Verteilte Daten
- Richardson, Chris. 2018: Microservices Patterns (Muster für Microservices). Manning Publications.
Zugehörige Ressourcen
Die folgenden Muster können für die Implementierung dieses Musters relevant sein:
- Bei der Choreographie nimmt jede Komponente des Systems an der Entscheidungsfindung zum Workflow einer Geschäftstransaktion teil, anstatt sich auf einen zentralen Steuerungspunkt zu verlassen.
- Kompensierende Transaktionen machen Vorgänge rückgängig, die von einer Reihe von Schritten durchgeführt wurden, und definieren schließlich einen konsistenten Vorgang, wenn mindestens ein Schritt fehlschlägt. Cloudbasierte Anwendungen, die komplexe Geschäftsprozesse und -workflows implementieren, befolgen oft dieses Modell der letztendlichen Konsistenz.
- Mithilfe der Wiederholung kann eine Anwendung vorübergehende Fehler behandeln, wenn sie versucht, eine Verbindung mit einem Dienst oder einer Netzwerkressource herzustellen, indem sie den fehlgeschlagenen Vorgang transparent wiederholt. Diese Wiederholung kann die Stabilität der Anwendung verbessern.
- Das Sicherungsentwurfsmuster verarbeitet Fehler, deren Behebung beim Herstellen einer Verbindung mit einem Remotedienst oder einer -ressource unterschiedlich lange dauern kann. Dies kann die Stabilität und Resilienz einer Anwendung verbessern.
- Das Muster für Überwachung der Integrität von Endpunkten implementiert Funktionsprüfungen in eine Anwendung, auf die externe Tools in regelmäßigen Abständen über verfügbare Endpunkte zugreifen können. Die Überwachung der Integrität von Endpunkten kann dabei helfen, sicherzustellen, dass Anwendungen und Dienste ordnungsgemäß ausgeführt werden.