Zum Hauptinhalt springen

Kein bestätigter Schreibvorgang bleibt zurück: Das Ownership- und Recovery-Fundament unter 12 Stunden Chaos

· 10 Minuten Lesezeit
Clustron Team
Engineering für verteilte Systeme

Kein Verlust bestätigter Schreibvorgänge, belegt über 12 Stunden Chaos

Der Happy Path eines verteilten Key/Value-Stores lässt sich leicht richtig umsetzen. Ein Schreibvorgang landet auf dem Primary, wird an die Replikate gestreamt, alle sind sich einig, weiter geht's. Wäre das die ganze Geschichte, wäre Langlebigkeit ein gelöstes Problem, und dieser Beitrag würde nicht existieren.

Die schweren Probleme liegen in den Nahtstellen — den kurzen, unbequemen Momenten, in denen sich der Cluster mitten in einem Übergang befindet. Ein Node startet mitten in einer Partitionsmigration neu. Ein Replikat fällt weit hinter den Active zurück, von dem es kopiert, und dann geht dieser Active per Failover an jemand anderen. Der Besitz einer Partition wechselt auf einen neuen Node, während noch Schreibvorgänge zum alten unterwegs sind. Jedes davon ist ein Fenster: eine Spanne von wenigen Sekunden, in der ein bestätigter Schreibvorgang — einer, dem der Client als erfolgreich gemeldet wurde — stillschweigend verschwinden kann, wenn die Übergabe nicht exakt stimmt. Nicht weil die Storage-Engine fehlerhaft wäre, sondern weil zwei Teile des Systems für einen Moment uneins darüber waren, wer die Wahrheit besitzt.

In diesem Beitrag geht es darum, wie Zaris diese Fenster schließt — und, worauf es wirklich ankommt, wie wir uns davon überzeugt haben, dass es funktioniert: indem wir den Cluster zwölf Stunden am Stück unter kontinuierlichem, gezieltem Chaos betrieben haben.

Die Aussage, ehrlich formuliert​

Seien wir gleich zu Beginn präzise, denn diese Art von Aussage verleitet zur Übertreibung. Die Garantie, die wir geben, lautet:

Kein bestätigter Schreibvorgang geht unter anhaltendem Chaos verloren — Node-Stopps, -Starts, -Neustarts, Failovers, Partitionsmigrationen und Scale-out-Churn —, nachgewiesen durch einen sauberen, kontinuierlichen 12-Stunden-Zertifizierungslauf.

Das ist nicht dasselbe wie „Zaris kann unter keinen Umständen Daten verlieren." Diesen Satz unterschreibt kein ehrlicher Ingenieur. Was wir validiert haben, ist eine konkrete, starke Eigenschaft: Sobald der Store einen Schreibvorgang gegenüber dem Client bestätigt hat, übersteht dieser Schreibvorgang den gesamten Katalog an Ownership-Übergangsfehlern, die wir auslösen können, und der Cluster konvergiert danach wieder in einen konsistenten Zustand. Der Zwölf-Stunden-Lauf ist ein Beleg für diese Aussage, kein Beweis universeller Unverwundbarkeit.

Es gibt eine zweite ehrliche Nuance, die für jeden wichtig ist, der ein Chaos-Log liest. Während des Chaos sehen Sie Schlüssel, die vorübergehend fehlen — ein Lesevorgang, der einen Schlüssel nicht findet, den er „finden müsste". Das ist erwartet und kein Datenverlust. Es geschieht, weil die Replikation einen asynchronen Schwanz hat (der Schreibvorgang wurde auf dem Active committet, hat aber das zufällig gelesene Replikat noch nicht erreicht) oder weil der Node, der den Schlüssel hält, in diesem Augenblick vom Chaos-Harness absichtlich gestoppt ist. Diese Schlüssel erscheinen bei der Konvergenz wieder. Die gesamte Disziplin der Langlebigkeits-Zertifizierung besteht darin, diese harmlose, selbstheilende Klasse von echtem Verlust zu trennen — einem Schlüssel, den kein überlebender Node je wieder herausgeben wird. Der Lauf besteht nur, wenn der echte Verlust null ist. Vorübergehend fehlend und dann wiederhergestellt wird toleriert; dauerhaft verschwunden nicht.

Die drei Nahtstellen und wie jede geschlossen wird​

Nahtstelle 1 — das gestrandete Replikat​

Stellen Sie sich eine Partition mit einer Active-Kopie und einem Replikat vor. Der Active fällt aus, das Replikat wird befördert, der alte Active kehrt als Replikat zurück — ein Promotion-/Demotion-Wechsel. In einer falschen Implementierung kann das frisch degradierte Replikat weit hinter dem neuen Active eingefroren enden: Es erhielt während des Wechsels den normalen Replikationsstrom nicht mehr, und nichts sagt ihm je, dass es aufholen soll. Es sitzt veraltet da und gibt vor, eine gültige Kopie zu sein. Fällt dann der neue Active aus, befördern Sie ein Replikat, dem Tausende Schreibvorgänge fehlen.

Die Abhilfe ist ein Replikat-Catch-up-Mechanismus. Ein Replikat, das als weit hinter seinem Active gestrandet erkannt wird — nicht nur kurz verzögert, sondern wirklich unterhalb des Active-Zustands eingefroren —, wird identifiziert und vom Active neu synchronisiert, statt zu verrotten. Die entscheidende Feinheit im Design ist, „normalen asynchronen Lag" von „festhängend" zu unterscheiden: Ein gesundes Replikat liegt immer ein wenig zurück, und das ist in Ordnung; ein gestrandetes liegt zurück und bewegt sich nicht. Die zweite Bedingung löst den erneuten Abruf aus.

Nahtstelle 2 — das Umschalten, das die einzige Kopie zerstört​

Bei einer Migration wechselt eine Partition den Owner. Der Quell-Node übergibt die Daten der Partition an das Ziel, und irgendwann erfolgt das Umschalten (Cut-over): Der Besitz wechselt, und die Quelle darf ihre Kopie verwerfen, um den Speicher freizugeben. Dieser Schritt „darf verwerfen" ist eine geladene Waffe. Verwirft die Quelle ihre Kopie aufgrund eines veralteten Umschaltnachweises — eines Signals, das „das Ziel hat es" sagt, obwohl das Ziel die Partition tatsächlich nicht vollständig übernommen hat —, haben Sie soeben die einzige gute Kopie dieser Daten gelöscht.

Die Abhilfe ist Umschalt-Sicherheit: Die Quelle zerstört ihre einzige Kopie nie aufgrund eines veralteten Nachweises. Ein Segment, das der neue Owner nicht nachweislich vollständig übernommen hat, wird behalten, nicht verworfen — gehalten, bis es wirklich sicher ist, loszulassen. Braucht das Ziel noch Daten, hält die Quelle sie noch und kann sie erneut ausliefern. Das Prinzip ist leicht formuliert und leicht falsch umzusetzen: Verwerfen ist die gefährliche Operation, also muss das Verwerfen seine Sicherheit beweisen, nicht umgekehrt.

Nahtstelle 3 — Recovery, die in beide Richtungen abgleicht​

Nach einem Churn-Sturm — viele Ausfälle dicht hintereinander — kann ein Replikat in beide Richtungen mit seinem Active uneins sein. Der offensichtliche Fall ist, zurückzuliegen (verpasste Schreibvorgänge). Der nicht offensichtliche Fall, der einen beißt, ist, voraus zu sein: Bei einer chaotischen Umverteilung kann ein Replikat einen Datensatz halten, den der aktuelle Active nicht mehr hat, etwa ein Update oder Delete, das eine Kopie erreichte, die andere aber nicht, bevor der Besitz wechselte.

Die Recovery muss also in beide Richtungen zur Konvergenz abgleichen — fehlende Datensätze in ein zurückliegendes Replikat ziehen und überzählige Datensätze eines vorauseilenden Replikats wegabgleichen —, bis Active und Replikat übereinstimmen. Ein Abgleich, der nur „zurück" behöbe, ließe die „voraus"-Divergenz für immer bestehen.

Eine Designentscheidung darin verdient besondere Erwähnung, denn sie trennt einen Mechanismus, der in einer Demo funktioniert, von einem, der zwölf Stunden überlebt. Der Abgleich auf Leader-Seite verwendet die Sync-State-Zähler wieder, die der Cluster ohnehin führt. Er baut kein neues Erkennungsnetz auf, das Probes über Nodes streut, und er bleibt abseits des heißen Map-Commit-Pfads — des kritischen Pfads, über den jeder Ownership-Wechsel ohnehin läuft. Vorhandene Signale wiederzuverwenden heißt, dass der Abgleich keinen eigenen neuen Fehlermodus und keine neue Latenz zu den ohnehin heikelsten Operationen hinzufügt. Der günstigste zuverlässige Detektor ist der, den Sie schon haben.

Das Gesamtbild​

Setzt man die drei Nahtstellen zusammen, ergibt die Langlebigkeitsgeschichte einen einzigen Ablauf: Ein Schreibvorgang wird bestätigt, Chaos tritt ein, und jeder Mechanismus fängt den zugehörigen Fehler ab, bevor er zu Verlust werden kann.

Der gestrichelte Pfad ist der Zweig der ehrlichen Nuance: die vorübergehend fehlenden Schlüssel, die sich von selbst auflösen. Auch sie fließen in die Konvergenz ein; sie zählten nur nie als Verlust.

Woher wir es wirklich wissen: die 12-Stunden-Zertifizierung​

Ein Designargument ist eine Hypothese. Der Test ist der Beleg. Deshalb betreiben wir gegen einen Live-Cluster eine kontinuierliche 12-Stunden-Chaos-Zertifizierung, und die Messlatte ist ein sauberer Lauf — sobald er das nicht ist, hat der Lauf einen Bug gefunden, und wir beheben ihn, statt auszuliefern.

Was „Chaos" konkret bedeutet, über die gesamte Dauer aufrechterhalten:

  • Zufälliger Node-Churn — Nodes werden fortlaufend gestoppt, gestartet und neu gestartet, sodass sich der Cluster praktisch nie in einem vollständig beruhigten Zustand befindet.
  • Failovers — Actives werden unter ihren Partitionen abgeschossen und erzwingen Promotions.
  • Partitionsmigrationen — der Besitz wandert zwischen Nodes, während die Workload läuft.
  • Scale-out-Churn — die Cluster-Mitgliedschaft selbst ändert sich unter Last.

Dagegen läuft eine Workload, die kontinuierlich zwei unabhängige Dinge prüft. Eine Suite prüft die Konvergenz der Datenebene: Sie treibt echte Schreibvorgänge, verfolgt, was bestätigt wurde, und verifiziert, dass jeder bestätigte Schreibvorgang nach der Konvergenz des Clusters weiterhin abrufbar ist — mit strikter Anwendung der Unterscheidung zwischen vorübergehend und echt, sodass ein Schlüssel, der fehlt, weil sein Node gerade gestoppt ist, nicht als Verlust gewertet wird, ein Schlüssel, den kein Node je zurückgibt, aber schon. Die andere Suite prüft die API-Stabilität: dass die Steuerungs- und Daten-APIs während des gesamten Churns korrekt funktionieren, nicht nur, dass Bytes überleben.

Der Lauf besteht nur, wenn beide Suites während der gesamten zwölf Stunden sauber bleiben: Die Konvergenz hält in beide Richtungen, kein echter Datenverlust, kein Replikat im Fehlerzustand, keine Partition mit dem falschen Owner. Genau dieses Ergebnis sollte die Arbeit am Fundament hervorbringen, und genau das hat der Ausdauerlauf gezeigt — Millionen bestätigter Operationen durch anhaltendes Chaos, echter Verlust null, jedes Ereignis eines vorübergehend fehlenden Schlüssels durch die harmlosen Fälle von asynchronem Schwanz bzw. gestopptem Node erklärt und bei Konvergenz aufgelöst.

Zwölf Stunden sind eine bewusste Länge. Eine Stunde Chaos zeigt, dass die gängigen Übergänge funktionieren. Die seltenen, hässlichen Verschränkungen — der Neustart, der genau in ein Umschalten fällt, das zweite Failover, bevor das erste Recovery abgeschlossen ist — sind pro Ereignis unwahrscheinlich; Sie sammeln also nur genug davon, um dem System zu vertrauen, indem Sie die Würfel lange rollen lassen. Die Nahtstellen sind fast per Definition die Zustände, in denen der Cluster am wenigsten Zeit verbringt. Man muss lange genug im Sturm bleiben, um sie immer wieder zu treffen.

Warum das wichtig ist, wenn Sie Zaris betreiben​

Wenn Sie einen Datenspeicher betreiben, wissen Sie bereits, dass die Ausfälle, die wehtun, nicht die sauberen sind. Ein Node, der sauber stirbt und tot bleibt, ist der einfache Fall. Die teuren Vorfälle sind die unordentlichen Überlappungen — ein Deployment, das Nodes durchrollt, während ein Rebalance läuft, ein Netzwerk-Aussetzer, der ein Failover auslöst, das mit einer Migration um die Wette läuft. Genau um diese Nahtstellen geht es hier.

Die praktische Erkenntnis: Zaris behandelt den Ownership-Übergang — Promotion, Demotion, Migration, Recovery — als erstklassigen Teil der Langlebigkeitsgeschichte, nicht als nachträglich an eine Storage-Engine geschraubtes Beiwerk. Ein bestätigter Schreibvorgang ist darauf ausgelegt, die Übergaben zu überstehen, das Verwerfen einer Kopie ist darauf ausgelegt, vorher seine eigene Sicherheit zu beweisen, und die Recovery ist darauf ausgelegt, ein divergentes Replikat wieder in Übereinstimmung zu bringen, in welche Richtung es auch abgedriftet ist. Und die Aussage ist durch kontinuierliche Chaos-Ausdauertests belegt, mit klar benanntem, ehrlichem Geltungsbereich: kein bestätigter Schreibvorgang geht unter anhaltendem Ausfall verloren, empirisch validiert — kein magisches Versprechen, dass Daten nie schiefgehen können.

Wenn Sie die Mechanik wissen möchten, wie Partitionen, Primaries und Replikate darunter zusammenspielen, beginnen Sie mit Partitionierung und Replikation und dem Konzept Replica in der Dokumentation. Das hier beschriebene Fundament hält diese Teile ehrlich, wenn der Cluster seinen schlimmsten Tag hat.