Replikation und Eventual Consistency
Replikation und Eventual Consistency
1) Warum eventual consistency
Wenn das System über Zonen/Regionen verteilt ist, führt die synchrone Aufzeichnung überall zu hoher Latenz und geringer Verfügbarkeit bei Netzwerkausfällen. Eventual consistency (EC) erlaubt eine vorübergehende Nicht-Synchronisation von Replikaten aus folgenden Gründen:- geringe Aufzeichnungsverzögerung (lokaler Empfang),
- bessere Zugänglichkeit bei Netzteilen,
- horizontale Skalierung.
Die Kernaufgabe ist die kontrollierte lasche Konsistenz: Der Nutzer sieht „ausreichend frische“ Daten, Domain-Invarianten bleiben erhalten, Konflikte werden erkannt und vorhersehbar gelöst.
2) Konsistenzmodelle - Was wir dem Kunden versprechen
Stark: Das Lesen sieht sofort den letzten Eintrag.
Bounded stale/read-not-older-than (RNOT): Lesen ist nicht älter als die Marke (LSN/Version/Zeit).
Causal: „Ursache-Wirkungs“ -Beziehungen werden beibehalten (A bis B).
Read-Your-Writes: Der Kunde sieht seine letzten Einträge.
Monotonische Lesungen: Jede nächste Lesung wird nicht „zurückgerollt“.
Sitzung: eine Reihe von Garantien innerhalb einer Sitzung.
Eventual: Wenn keine neuen Einträge vorhanden sind, laufen alle Replikate zusammen.
Praxis: Kombinieren Sie Session + RNOT auf kritischen Pfaden und Eventual auf Vitrinen/Caches.
3) Replikation: Mechanik und Anti-Entropy
Synchron (Quorum/RAFT): Die Aufzeichnung gilt nach Bestätigung durch N Knoten als erfolgreich; Mindestrpo, über p99.
Asynchron: der Führer commitit lokal, verteilt das Protokoll später; niedrige Latenz, RPO> 0.
Physikalisch (WAL/binlog): schnell, homogen.
Logisch/CDC: Änderungsfluss auf Zeilen-/Ereignisebene, flexibles Routing, Filter.
Anti-Entropy: periodische Abstimmungen und Reparaturen (Merkle-Bäume, Hash-Vergleich, Hintergrund-Re-Sync).
4) Versionskennungen und Kausalitätsaufträge
Monotone Versionen: increment/LSN/epoch; einfach, aber nicht kodieren Parallelität.
Lamport Timestamp: Teilreihenfolge nach logischer Uhr.
Vektoruhr: Erfasst parallele Zweige und ermöglicht die Erkennung von Konfliktupdates (concurrent).
Hybrid/TrueTime/Clock-SI: Logik „nicht vor T“ für die globale Ordnung.
Empfehlung: für CRDT/Konflikt-Updates - Vektoruhr; für „nicht älter“ - LSN/GTID.
5) Konflikte: Entdeckung und Lösung
Typische Situationen: Schreiben von zwei Regionen in das gleiche Objekt.
Strategien:1. Last-Write-Wins (LWW) nach Stunden-/Logikstempel - einfach, kann aber Upgrades „verlieren“.
2. Merge-Funktionen nach Domänenlogik:- Zählfelder addieren sich (G-Counter/PN-Counter),
- Mengen werden mit „add-wins/remove-wins“ kombiniert,
- Beträge/Salden - nur über Transaktionsprotokolle, nicht über eine einfache LWW.
- 3. CRDT (Converged Types): G-Counter, OR-Set, LWW-Register, RGA für Listen.
- 4. Operative Transformationen (selten für DB, häufiger für Redakteure).
- 5. Manuelle Lösung: Konflikt in „inbox“, der Benutzer wählt die richtige Version.
Regel: Domain-Invarianten diktieren die Strategie. Für Geld/Guthaben - vermeiden Sie LWW; Transaktionen/Ereignisse mit Kompensation verwenden.
6) Datensatzgarantien und Idempotenz
Idempotente Schlüssel auf Befehlen (payment, withdraw, create) → Wiederholung ist sicher.
Deduplizierung am „Eingang“ (inbox) und „Ausgang“ (outbox) nach idempotence key/serial number.
Exactly-once ist ohne starke Voraussetzungen unerreichbar; üben Sie at-least-once + idempotence.
Outbox/Inbox-Muster: Eintrag in die DB und Veröffentlichung des Ereignisses ist atomar (lokale Transaktion), der Empfänger verarbeitet per idempotency-key.
7) Lesungen „nicht älter als X“ (RNOT)
Techniker:- LSN/GTID-Gate: Der Client überträgt die Mindestversion (aus der Schreibantwort), der Router/Proxy sendet an das Replikat, das LSN ≥ X eingeholt hat, andernfalls an den Leader.
- Time-bound: „werde nicht älter 2 Sekunden“ ist ein einfaches SLA ohne Versionen.
- Session-Pinning: Nach der Aufzeichnung von N Sekunden lesen wir nur den Leader (Read-Your-Writes).
8) Änderungsflüsse und Cacheaushandlung
CDC → Ereignisbus (Kafka/Pulsar) → Verbraucher (Caches, Indizes, Schaufenster).
Behinderung durch Caches: topics' invalidate: {ns}: {id}'; idempotent Verarbeitung.
Rebuild/Backfill: Wenn Sie nicht synchron sind, erstellen Sie Projektionen aus dem Ereignisprotokoll neu.
9) Sagas und Vergütungen (serviceübergreifende Transaktionen)
In der EC-Welt werden langlebige Operationen in Schritte mit Ausgleichsmaßnahmen unterteilt:- Orchestrierung: Der Koordinator ruft die Schritte und deren Kompensation auf.
- Choreografie: Schritte reagieren auf Ereignisse und veröffentlichen die nächsten selbst.
Invarianten (Beispiel): „Balance ≥ 0“ - Überprüfung an den Schrittgrenzen + Kompensation bei Abweichung.
10) Multi-Region und Netzwerk-Splits
Local-write, async-replicate: Eintrag in der lokalen Region + Lieferung an andere (EC).
Geo-Fencing: Daten werden an die Region „geklebt“ (geringe Latenz, weniger Konflikte).
Quorum-DBs (Raft) für CP-Daten; Caches/Schaufenster - AP/EC.
Split-Brain-Plan: Wenn die Verbindung verloren geht, arbeiten die Regionen weiterhin innerhalb der Domänenlimits (Schreibfencing, Quoten), dann - reconcile.
11) Beobachtbarkeit und SLO
Metriken:- Replica lag: time/LSN-distance/offset (p50/p95/p99).
- Staleness: Anteil der Antworten, die älter als die Schwelle sind (z.B.> 2s oder LSN
- Konfliktrate: Häufigkeit von Konflikten und erfolgreichen Zusammenschlüssen.
- Convergence time: Die Konvergenzzeit der Replikate nach dem Peak.
- Reconcile backlog: Volumen/Zeit der Nachzügler.
- RPO/RTO nach Datenkategorie (CP/AP).
- Lag> Ziel, wachsende Konflikte, „lange“ Fenster der Unvereinbarkeit.
12) Design des Datenschemas unter EC
Explizite Version/Vektor in jedem Datensatz (Spalten 'version', 'vc').
Nur Append-Protokolle für kritische Invarianten (Salden, Gebühren).
Ereignis-IDs (snowflake/ULIDs) für Reihenfolge und Deduplizierung.
Felder mit kommutativer Natur (Zähler, Menge) → Kandidaten für CRDT.
API-Design: PUT mit if-match/etag, PATCH mit Precondition.
13) Speicher- und Lesemuster
Read model/CQRS: Schreiben in die „Quelle“, Lesen aus Projektionen (kann zurückbleiben → Anzeige „aktualisiert“...).
Stale-OK Routen (Verzeichnis/Band) vs Strict (Wallet/Limits).
Sticky/Bounded-stale Flags in der Abfrage (Überschrift „x-read-consistency“).
14) Implementierung Checkliste (0-45 Tage)
0-10 Tage
Kategorisieren Sie die Daten: CP-kritisch (Geld, Aufträge) vs EU/stale-OK (Kataloge, Suchindizes).
Bestimmen Sie den SLO des Steals (z. B. „nicht älter als 2s“), die Zielverzögerungen.
Aktivieren Sie Objektversionierung und idempotency-keys in der API.
11-25 Tage
Implementieren Sie CDC und Outbox/Inbox, Cache-Invaliditätsrouten.
Fügen Sie RNOT (LSN-Gate) und Session-Pinning zu den schreibkritischen Pfaden hinzu.
Implementieren Sie mindestens eine Merge-Strategie (LWW/CRDT/Domain) und ein Konfliktprotokoll.
26-45 Tage
Automatisieren Sie Anti-Entropy (Abstimmungen/Reparaturen) und Steyling-Berichte.
Halten Sie einen Spieletag: Trennung des Netzwerks, Ausbruch von Konflikten, Erholung.
Visualisieren Sie auf Dashboards: lag, staleness, conflict rate, convergence.
15) Anti-Muster
Blind LWW für kritische Invarianten (Verlust von Geld/Punkten).
Das Fehlen von idempotency → doppelte Operationen bei Retrays.
Das „starke“ Modell → übermäßige p99-Schwänze und Zerbrechlichkeit bei Ausfällen.
Es gibt keine RNOT/Session-Garantien → UX „blinkt“, Benutzer „sehen“ ihre Änderungen nicht.
Versteckte Nicht-Synchronisation von Cache und Quelle (keine CDC/Behinderung).
Das Fehlen des Tools reconcile/anti-entropy - die Daten „seit Jahrhunderten“ gehen auseinander.
16) Reifegradkennzahlen
Replica lag p95 ≤ Ziel (z. B. ≤ 500 ms innerhalb einer Region ≤ 2 s Interregionen).
Staleness SLO erfüllt ≥ 99% der Anfragen auf „strengen“ Routen.
Conflict resolution success ≥ 99. 9%, durchschnittliche Auflösungszeit ≤ 1 min.
Convergence Zeit nach Spitzen - Minuten, nicht Stunden.
100% der „monetären“ Transaktionen werden mit idempotency-Schlüsseln und outbox/inbox abgedeckt.
17) Rezepte (Schnipsel)
If-Match/ETag (HTTP)
PUT /profile/42
If-Match: "v17"
Body: { "email": "new@example.com" }
Wenn die Version geändert wurde - „412 Precondition Failed“ → löst der Client den Konflikt.
Abfrage „nicht älter als LSN“ (Pseudo)
x-min-lsn: 16/B373F8D8
Der Router wählt ein Replikat mit 'replay _ lsn ≥ x-min-lsn', ansonsten - der Führer.
CRDT G-Counter (Idee)
Jede Region speichert ihren Zähler; das Ergebnis ist die Summe aller Komponenten; Replikation - Der Vorgang ist kommutativ.
18) Schlussfolgerung
Eventual consistency ist kein Kompromiss aus Qualität, sondern ein bewusster Vertrag: Irgendwo zahlen wir Frische für Geschwindigkeit und Verfügbarkeit, aber wir schützen kritische Invarianten mit Domain-Strategien und Tools. Geben Sie die Versionen, idempotency, RNOT/Session Garantie, CDC und Anti-Entropy, messen lag/staleness/Konflikte - und Ihr verteiltes System wird schnell, stabil und vorhersehbar konvergieren auch unter Ausfällen und Spitzenlasten.