Sagas und verteilte Transaktionen
Eine Saga ist eine langfristige Geschäftstransaktion, die in eine Reihe lokaler Schritte in verschiedenen Diensten/Speichern unterteilt ist. Jeder Schritt hat eine kompensierende Wirkung, die die Wirkung des Schrittes bei einem Teilausfall zurücknimmt. Im Gegensatz zu 2PC/3PC halten Sagas globale Blockaden nicht zurück und eignen sich für Microservices, Multi-Regionen und hohe Lasten, bei denen eine eventuelle Consistency zulässig ist.
1) Wann man Sagas wählt (und wann nicht)
Geeignet für:- Lange/mehrstufige Geschäftsprozesse (Bestellung → Zahlung → Reserve → Lieferung).
- Verschiedene Domains und Depots, in denen es keine gemeinsame Transaktion gibt.
- Sie benötigen eine hohe Verfügbarkeit und eine horizontale Skalierung.
- Die feste ACID-Atomarität ist kritisch (z.B. Übertragung großer Mengen innerhalb eines Registers).
- Es gibt keine eindeutige Kompensierbarkeit (Sie können den Effekt nicht „einmal reservieren“ oder rückgängig machen).
- Rechtliche/regulatorische Einschränkungen erfordern eine strikte Isolation und eine „sofortige“ Invarianz.
2) Saga-Modelle
1. Orchestrierung (Saga Orchestrator): Der zentrale Koordinator verwaltet die Schritte und Kompensationen.
Vorteile: klarer Fluss, Fehlerkontrolle, vereinfachte Telemetrie.
Nachteile: Zentralisierungspunkt, Risiko eines „dicken“ Koordinators.
2. Choreographie: kein Zentrum - Schritte werden durch Ereignisse eingeleitet („Service A hat X gemacht → Service B reagiert“).
Vorteile: schwache Konnektivität, einfache Skalierung.
Nachteile: Es ist schwieriger, den Fluss zu verfolgen/zu debuggen, das Risiko eines „Wachstums“ der Regeln.
3. TCC (Try-Confirm/Cancel): Jeder Schritt ist eine „Reservierung“ (Try), dann eine Bestätigung (Confirm) oder eine Stornierung (Cancel).
Vorteile: Näher am Pseudo-Zwei-Phasen-Protokoll, verwaltete Ressourcen.
Nachteile: teurer in der Implementierung von Schnittstellen; erfordert Timeouts von „Try“ -Haltern.
3) Stufen- und Kompensationsdesign
Invarianten: Formulieren Sie klar, was „vor/nach“ einem Schritt wahr sein sollte (z. B. „Rest ≥ 0“).
Kompensation ≠ umgekehrte Transaktion: Dies ist eine logische Aktion, die den Geschäftseffekt aufhebt (Refund, Release, Restore).
Idempotenz: Sowohl der Schritt als auch der Kompensator müssen sicher wiederholt werden (durch 'operation _ id').
Timeouts: Jeder Schritt hat eine Deadline; Verspätung löst Entschädigung aus.
Nicht wiederkehrende Effekte: Diese separat erfassen (Benachrichtigungen, E-Mail) und „best effort“ zulassen.
4) Kohärenz und Ordnung
Eventual consistency: Benutzer können temporäre Diskrepanzen sehen; UX - mit „Erwartung „/Spinnern/Status.
Schlüsselreihenfolge: Gruppieren Sie Schaltschritte nach Geschäftsschlüssel (order_id), um Ereignisse zu organisieren.
Deduplizierung: Speichern Sie ein Protokoll der Behandlungen ('operation _ id' → Status) mit TTL.
5) Transport und Zuverlässigkeit
Outbox-Muster: Schreiben Sie das Ereignis in die lokale Tabelle „outbox“ innerhalb derselben Transaktion und veröffentlichen Sie es dann asynchron auf dem Bus.
Inbox/Idempotency Store: Auf der Verbraucherseite befindet sich ein Protokoll bereits verarbeiteter Nachrichten.
Exactly-once ist effektiv: „outbox + idempotent consumer“ gibt praktisch „genau einmal“.
DLQ: für „giftige“ Nachrichten mit reichhaltigen Meta-Informationen und sicherem Redrive.
6) Fehlerrichtlinien, Retrays, Backoff
Wir wiederholen nur die idempotenten Schritte; Schreibvorgänge - mit 'Idempotency-Key'.
Exponentieller Backoff + Jitter; Begrenzung der Versuche und der Gesamtdauer der Saga.
Bei systemischer Degradation - Circuit Breaker und graceful degradation (z.B. Abschaffung des sekundären Fichi-Teils der Saga).
Geschäftskonflikte ('409') - Wiederholung nach Vereinbarung oder Ausgleich und Abschluss.
7) Orchestrator: Aufgaben und Struktur
Funktionen:- „PENDING → RUNNING → COMPENSATING → DONE/FAILED“
- Planung von Schritten, Deadlines, Timeouts, Retrays.
- Routing von Ereignissen und Starten von Entschädigungen.
- Idempotenz der Aktivitäten des Koordinators (Teamprotokoll).
- Beobachtbarkeit: Korrelation 'saga _ id' in Protokollen/Trays/Metriken.
- Tabellen 'saga', 'saga _ step', 'commands', 'outbox'.
- Indizes nach 'saga _ id', 'business _ key', 'status', 'next _ run _ at'.
8) Choreographie: Regeln und Schutz vor „Schneeball“
Ereignisverträge: Schemata und Versionierung (Avro/Proto/JSON Schema).
Klare Semantik: „Faktenereignis“ gegen „Befehl“.
Kettenabbruch: Der Dienst, der die Diskrepanz entdeckt, veröffentlicht das Ereignis' Failed '/' Compensate'.
Alarm und Alert für „Endlosschleifen“.
9) TCC: praktische Details
Try: Ressourcenreserve mit TTL.
Confirm: Fixierung, Freigabe von Zeitsperren.
Abbrechen: Zurücksetzen der Reserve (ohne Nebenwirkungen).
Garbage Collection: Automatische Stornierung Try nach TTL (idempotent Cancel).
Idempotent Confirm/Cancel: Die Wiederholung ist sicher.
10) Beispiel (Wortschema) - „Bestellung mit Zahlung und Lieferung“
1. CreateOrder (lokal) → outbox: 'OrderCreated'.
2. PaymentService: Reserve „Try“ (TCC); bei Erfolg der → „PaymentReserved“, bei Ausfall der → „PaymentFailed“.
3. InventoryService: Warenreserve; Das → „InventoryFailed“ fehlt.
4. ShippingService: Erstellen Sie einen Lieferslot (stornierbar).
5. Wenn ein Schritt „fehlgeschlagen“ ist → löst der Orchestrator die Kompensation in umgekehrter Reihenfolge aus: „CancelShipping“ → „ReleaseInventory“ → „PaymentCancel“.
6. Wenn alles in Ordnung ist → 'PaymentConfirm' → 'OrderConfirmed'.
11) Pseudocode des Orchestrators
pseudo startSaga(saga_id, order_id):
steps = [ReservePayment, ReserveInventory, BookShipment, ConfirmPayment]
for step in steps:
res = execWithRetry(step, order_id)
if!res.ok:
compensateInReverse(steps_done(order_id))
return FAIL return OK
execWithRetry(step, key):
for attempt in 1..MAX:
try:
return step.run(key) # идемпотентно catch RetryableError:
sleep(backoff(attempt))
catch NonRetryableError:
return FAIL return FAIL
compensateInReverse(done_steps):
for step in reverse(done_steps):
step.compensate() # идемпотентно
12) Beobachtbarkeit und operative SLOs
Tracing: single' saga _ id', Anmerkungen 'step', 'attempt', 'decision' (run/compensate/skip).
Metriken:- Erfolg/Sagenfehler (%), durchschnittliche Dauer, p95/p99.
- Anteil der kompensierten Sagen, Top-Entschädigungsgründe.
- Warteschlangen/Outbox Lags, Retrays in Schritten.
- Logs/Audit: Entscheidungen des Orchestrators, Ressourcen-IDs, Geschäftsschlüssel.
13) Testen und Chaos
Fehlerinjektion in jedem Schritt: Timeouts, '5xx', Geschäftskonflikte.
Out-of-Order-Ereignisse, Duplikate, Auslassungen (Drop).
Lange Latenzschwänze → Überprüfung von Terminen und Entschädigungen.
Massensages → Überprüfung von WFQ/DRR und Caps in Warteschlangen, kein „Head-of-Line-Blocking“.
Redrive von DLQ in Schritten und in einer ganzen Saga.
14) Multi-Tenant, Regionen, Compliance
'tenant _ id/plan/region' -Tags in Veranstaltungen und Sagenspeichern.
Residency: Daten/Ereignisse verlassen die Region nicht; cross-regionale Sagas als Verbände lokaler Sagen + Aggregationsereignisse gestalten.
Priorisierung: VIP-Sagas haben mehr Quotengewicht; Isolierung der Worker per tenant.
15) Checkliste vor dem Verkauf
- Jeder Schritt hat einen klaren Kompensator, beide sind idempotent.
- Ausgewählte Vorlage: Orchestrierung/Choreografie/TSS; Die Grenzen der Verantwortung werden beschrieben.
- Outbox/Inbox implementiert, Deduplizierung durch 'operation _ id'.
- Retrai-Richtlinien: Backoff mit Jitter, Grenzen für Versuche und allgemeine Saga-Deadline.
- Die Veranstaltungsverträge sind versioniert, es gibt eine Validierung des Schemas.
- DLQ und Secure Redrive sind konfiguriert.
- Telemetrie: Metriken, Tracing, Korrelation 'saga _ id'.
- Operational playbooks: manual cancel/force-confirm, Einbettung von „schwebenden“ Sagen.
- Chaos und Belastungstests werden bestanden, SLO/Fehlerbudget ermittelt.
16) Typische Fehler
Es gibt keinen Kompensator oder es ist „unrein“ (hat Nebenwirkungen).
Es gibt keine Idempotenz/Dedup - Takes und „Swing“ -Zustände.
„Saga in Saga“ ohne klare Grenzen - Zyklen und gegenseitige Blockaden.
Es gibt keine Deadlines → „ewige“ Sagas und Ressourcenlecks.
Der Orchestrator speichert den Zustand „im Gedächtnis“ ohne stabilen Stor.
Choreographie ohne Telemetriezentrum → „unsichtbare“ Störungen.
Undurchsichtige UX: Benutzer sehen keine Zwischenstände.
17) Schnelle Rezepte
SaaS-Klassiker: Orchestrierung + Outbox/Inbox, exponentieller Backoff, DLQ, Saga-Status in der Benutzeroberfläche.
Starke Invarianten pro Ressource: TCC mit TTL Reserve und GC Cancel.
Hohe Lautstärke/Belastung: Choreographie der Ereignisse + strenge Idempotenz und Metriken nach Schlüssel.
Multi-Region: lokale Sagas + letzte Aggregate; globale Blockaden zu vermeiden.
Schluss
Sagas sind eine Möglichkeit, vorhersehbare Konsistenz in verteilten Systemen ohne globale Sperren zu erhalten. Klare Kompensatoren, Idempotenz, zuverlässige Lieferung (Outbox/Inbox), die Disziplin von Timeouts und Retrains sowie Telemetrie und Playbooks sind der Schlüssel, um sicherzustellen, dass komplexe Geschäftsprozesse stabil und lesbar bleiben, wenn die Last, die Anzahl der Dienste und die Geografien steigen.