Das Saga-Designmuster trägt dazu bei, die Datenkonsistenz in verteilten Systemen aufrechtzuerhalten, indem Transaktionen über mehrere Dienste hinweg koordiniert werden. Eine Saga ist eine Sequenz lokaler Transaktionen, bei denen jeder Dienst seinen Betrieb ausführt und den nächsten Schritt durch Ereignisse oder Nachrichten initiiert. Wenn ein Schritt in der Sequenz fehlschlägt, führt die Saga Ausgleichstransaktionen aus, um die abgeschlossenen Schritte rückgängig zu machen, wobei die Datenkonsistenz beibehalten wird.
Kontext und Problem
Eine Transaktion stellt eine Arbeitseinheit dar, die mehrere Vorgänge umfassen kann. Innerhalb einer Transaktion bezieht sich ein Ereignis auf eine Zustandsänderung, die sich auf eine Entität auswirkt. Ein -Befehl kapselt alle Informationen, die zum Ausführen einer Aktion oder auslösen eines nachfolgenden Ereignisses erforderlich sind.
Transaktionen müssen den Grundsätzen der Atomität, Konsistenz, Isolation und Haltbarkeit (ACID) entsprechen.
- Atomität: Alle Vorgänge sind erfolgreich oder nicht.
- Konsistenz: Datenübergänge von einem gültigen Zustand in einen anderen.
- Isolation: Gleichzeitige Transaktionen liefern dieselben Ergebnisse wie sequenzielle Transaktionen.
- Haltbarkeit: Nach dem Commit bleiben Änderungen auch bei Fehlern bestehen.
In einem einzigen Dienst folgen Transaktionen ACID-Prinzipien, da sie innerhalb einer einzelnen Datenbank arbeiten. Das Erreichen der ACID-Compliance über mehrere Dienste hinweg ist jedoch komplexer.
Herausforderungen in Microservices-Architekturen
Microservices-Architekturen weisen in der Regel jeder Microservice-eine
- Jeder Dienst kapselt seine eigenen Daten.
- Jeder Dienst kann die am besten geeignete Datenbanktechnologie und das schema für seine spezifischen Anforderungen verwenden.
- Unabhängige Skalierung von Datenbanken für jeden Dienst.
- Fehler in einem Dienst sind von anderen isoliert.
Trotz dieser Vorteile erschwert diese Architektur die dienstübergreifende Datenkonsistenz. Herkömmliche Datenbankgarantien wie ACID gelten nicht direkt für mehrere unabhängig verwaltete Datenspeicher. Aufgrund dieser Einschränkungen sind Architekturen, die auf interprocess communication (IPC) oder herkömmlichen Transaktionsmodellen basieren, wie z. B. zweistufiger Commit (2PC)-Protokoll, häufig besser für das Saga-Muster geeignet.
Lösung
Das Saga-Muster verwaltet Transaktionen, indem sie in eine Abfolge von lokalen Transaktionen unterteilt werden (siehe Abbildung 1).
Abbildung 1. Eine Saga mit drei Diensten.
Jede lokale Transaktion:
- Schließt seine Arbeit atomisch innerhalb eines einzigen Diensts ab.
- Aktualisiert die Datenbank des Diensts.
- Initiiert die nächste Transaktion über ein Ereignis oder eine Nachricht.
- Wenn eine lokale Transaktion fehlschlägt, führt die Saga eine Reihe von Ausgleichstransaktionen aus, um die von den vorherigen lokalen Transaktionen vorgenommenen Änderungen rückgängig zu machen.
Schlüsselkonzepte im Saga-Muster
Kompensierbare Transaktionen: Transaktionen, die andere Transaktionen rückgängigmachen oder mit dem gegenteiligen Effekt ausgleichen können. Wenn ein Schritt in der Saga fehlschlägt, machen Ausgleichstransaktionen die Änderungen rückgängig, die die kompensierbaren Transaktionen vorgenommen haben.
Pivottransaktion: Die Pivottransaktion dient als "Point of no return" in der Saga. Sobald die Pivottransaktion erfolgreich war, sind kompensierbare Transaktionen (die rückgängig gemacht werden können) nicht mehr relevant. Alle nachfolgenden Maßnahmen müssen abgeschlossen werden, damit das System einen konsistenten Endzustand erreicht. Eine Pivottransaktion kann je nach Ablauf der Saga in verschiedene Rollen fallen:
unwiderruflichen (nicht kompensierbaren): Es kann nicht rückgängig gemacht oder wiederholt werden.
Grenze zwischen umkehrbarem und zugesicherten: Es kann sich um die letzte rückgängig gemachte (kompensierbare) Transaktion handeln, oder es kann der erste retryable-Vorgang in der Saga sein.
Retryable transactions: Diese Transaktionen folgen der Pivottransaktion. Retryable transactions are idempotent and ensure that the saga can reach its final state, even if temporary failures occur. Es garantiert, dass die Saga letztendlich einen konsistenten Zustand erreicht.
Saga Implementierungsansätze
Es gibt zwei gängige Saga-Implementierungsansätze, Choreographie und Orchestrierung. Jeder Ansatz verfügt über eigene Herausforderungen und Technologien, um den Workflow zu koordinieren.
Choreographie
In der Choreographie tauschen Dienste Ereignisse ohne einen zentralen Controller aus. Mit Choreographie veröffentlicht jede lokale Transaktion Domänenereignisse, die lokale Transaktionen in anderen Diensten auslösen (siehe Abbildung 2).
Abbildung 2. Eine Saga, die Choreographie verwendet.
Vorteile der Choreographie | Nachteile der Choreographie |
---|---|
Gut für einfache Workflows mit wenigen Diensten und benötigen keine Koordinationslogik. | Workflow kann beim Hinzufügen neuer Schritte verwirrend werden. Es ist schwierig zu verfolgen, welche Saga-Teilnehmer auf welche Befehle hören. |
Für die Koordination ist kein anderer Dienst erforderlich. | Es besteht das Risiko einer zyklischen Abhängigkeit zwischen saga-Teilnehmern, da sie die Befehle der anderen nutzen müssen. |
Führt keinen einzigen Fehlerpunkt ein, da die Verantwortlichkeiten über die Saga-Teilnehmer verteilt werden. | Integrationstests sind schwierig, da alle Dienste ausgeführt werden müssen, um eine Transaktion zu simulieren. |
Orchestrierung
In der Orchestrierung verarbeitet ein zentralisierter Controller (Orchestrator) alle Transaktionen und teilt den Teilnehmern mit, welche Operation basierend auf Ereignissen ausgeführt werden soll. Der Orchestrator führt Saga-Anforderungen aus, speichert und interpretiert die Zustände jeder Aufgabe und behandelt die Fehlerwiederherstellung mit Ausgleichstransaktionen (siehe Abbildung 3).
Abbildung 3. Eine Saga, die Orchestrierung verwendet.
Vorteile der Orchestrierung | Nachteile der Orchestrierung |
---|---|
Besser geeignet für komplexe Workflows oder beim Hinzufügen neuer Dienste. | Andere Entwurfskomplexität erfordert eine Implementierung einer Koordinationslogik. |
Vermeidet zyklische Abhängigkeiten, da der Orchestrator den Fluss verwaltet. | Führt einen Fehlerpunkt ein, da der Orchestrator den vollständigen Workflow verwaltet. |
Eine klare Trennung der Verantwortlichkeiten vereinfacht die Dienstlogik. |
Probleme und Überlegungen
Berücksichtigen Sie bei der Implementierung des Saga-Musters die folgenden Punkte:
Shift in Design Thinking: Die Übernahme des Saga-Musters erfordert eine andere Denkweise, die sich auf die Koordination von Transaktionen konzentriert und die Datenkonsistenz über mehrere Mikroservices hinweg gewährleistet.
Komplexität der Debugging-Sagas: Debugging-Sagas können komplex sein, insbesondere wenn die Anzahl der teilnehmenden Dienste wächst.
Unumkehrbare lokale Datenbankänderungen: Daten können nicht zurückgesetzt werden, da die Saga-Teilnehmer Änderungen an ihren jeweiligen Datenbanken übernehmen.
Behandlung vorübergehender Fehler und idempotenz: Das System muss vorübergehende Fehler effektiv behandeln und die Idempotenz sicherstellen, wobei die Wiederholung desselben Vorgangs das Ergebnis nicht ändert. Weitere Informationen finden Sie unter Idempotent-Nachrichtenverarbeitung.
Notwendigkeit der Überwachung und Verfolgung von Sagas: Überwachung und Nachverfolgung des Workflows einer Saga sind unerlässlich, um die operative Aufsicht aufrechtzuerhalten.
Einschränkungen des Ausgleichs von Transaktionen: Ausgleichstransaktionen sind möglicherweise nicht immer erfolgreich, wodurch das System möglicherweise inkonsistent ist.
Potenzielle Datenanomalien in Sagas
Datenanomalien sind Inkonsistenzen, die auftreten können, wenn Sagas über mehrere Dienste hinweg ausgeführt werden. Da jeder Dienst seine eigenen Daten (Teilnehmerdaten) verwaltet, gibt es keine integrierte Isolierung über Dienste hinweg. Diese Einrichtung kann zu Dateninkonsistenzen oder Dauerhaftigkeitsproblemen führen, z. B. teilweise angewendete Updates oder Konflikte zwischen Diensten. Häufige Probleme sind:
Verlorene Updates: Wenn eine Saga Daten ändert, ohne änderungen von einer anderen Saga zu berücksichtigen, führt sie zu überschriebenen oder fehlenden Updates.
Dirty liest: Wenn eine Saga oder Transaktion Daten liest, die eine andere Saga geändert, aber noch nicht abgeschlossen hat.
Fuzzy (nicht wiederholbar) liest: Wenn verschiedene Schritte in einer Saga inkonsistente Daten lesen, da Aktualisierungen zwischen den Lesevorgängen auftreten.
Strategien zur Behebung von Datenanomalien
Um diese Anomalien zu reduzieren oder zu verhindern, sollten Sie die folgenden Gegenmaßnahmen berücksichtigen:
Semantiksperre: Verwenden Sie Sperrungen auf Anwendungsebene, bei denen die kompensierbare Transaktion einer Saga ein Semaphor verwendet, um anzugeben, dass ein Update ausgeführt wird.
Kommutative Updates: Designupdates, sodass sie in beliebiger Reihenfolge angewendet werden können und gleichzeitig dasselbe Ergebnis erzeugen, wodurch Konflikte zwischen Sagas reduziert werden.
pessimistische Ansicht: Ordnen Sie die Sequenz der Saga neu an, sodass Datenaktualisierungen in wiederholungsfähigen Transaktionen auftreten, um schmutzige Lesevorgänge zu beseitigen. Andernfalls könnte eine Saga schmutzige Daten lesen (nicht ausgelassene Änderungen), während eine andere Saga gleichzeitig eine kompensierbare Transaktion ausführt, um ihre Updates zurückzufahren.
Werteerneut lesen: Überprüfen Sie, ob die Daten unverändert bleiben, bevor Sie Aktualisierungen vornehmen. Wenn sich Daten ändern, beenden Sie den aktuellen Schritt, und starten Sie die Saga nach Bedarf neu.
Versionsdateien: Verwalten Sie ein Protokoll aller Vorgänge in einem Datensatz, und stellen Sie sicher, dass sie in der richtigen Reihenfolge ausgeführt werden, um Konflikte zu verhindern.
risikobasierte Parallelität (nach Wert): Wählen Sie dynamisch den entsprechenden Parallelitätsmechanismus basierend auf dem potenziellen Geschäftsrisiko aus. Verwenden Sie beispielsweise Sagas für Updates mit geringem Risiko und verteilte Transaktionen für risikoreiche Transaktionen.
Wann dieses Muster verwendet werden soll
Verwenden Sie das Saga-Muster, wenn Sie Folgendes benötigen:
- Stellen Sie die Datenkonsistenz in einem verteilten System ohne enge Kopplung sicher.
- Rollback oder Ausgleich, wenn einer der Vorgänge in der Sequenz fehlschlägt.
Das Saga-Muster eignet sich weniger für:
- Eng gekoppelte Transaktionen.
- Ausgleich von Transaktionen, die in früheren Teilnehmern auftreten.
- Zyklische Abhängigkeiten.
Nächste Schritte
- verteilte Daten
- Richardson, Chris. 2018: Microservices Patterns. Manning Publikationen.
Verwandte Ressourcen
Die folgenden Muster können auch bei der Implementierung dieses Musters hilfreich sein:
- Choreographie verfügt über jede Komponente des Systems an dem Entscheidungsprozess über den Workflow einer Geschäftstransaktion, anstatt sich auf einen zentralen Kontrollpunkt zu verlassen.
- Ausgleichstransaktionen Von einer Reihe von Schritten ausgeführte Arbeit rückgängig zu stellen und schließlich einen konsistenten Vorgang zu definieren, wenn ein oder mehrere Schritte fehlschlagen. In der Cloud gehostete Anwendungen, die komplexe Geschäftsprozesse und Workflows implementieren, folgen häufig diesem späteren Konsistenzmodell.
- Versuchen Sie es erneut, eine Anwendung vorübergehende Fehler behandeln kann, wenn sie versucht, eine Verbindung mit einem Dienst oder einer Netzwerkressource herzustellen, indem sie den fehlgeschlagenen Vorgang transparent wiederholen. Wiederholungsversuche können die Stabilität der Anwendung verbessern.
- Schaltkreistrennzeichen Fehler behandelt, bei denen beim Herstellen einer Verbindung mit einem Remotedienst oder einer Ressource eine variable Zeit für die Wiederherstellung erforderlich ist. Der Schaltkreisschalter kann die Stabilität und Resilienz einer Anwendung verbessern.
- Überwachung des Integritätsendpunkts implementiert funktionale Prüfungen in einer Anwendung, auf die externe Tools in regelmäßigen Abständen über verfügbar gemachte Endpunkte zugreifen können. Die Integritätsendpunktüberwachung kann dabei helfen, zu überprüfen, ob Anwendungen und Dienste ordnungsgemäß ausgeführt werden.