Zum Hauptinhalt springen

25 Posts getaggt mit "Verteilte Systeme"

Artikel über Architektur und Design verteilter Systeme.

Alle Tags anzeigen

Viele Keys, wenige Round-Trips: Wie Zaris eine Bulk-Operation per Fan-out verteilt

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

Eine Bulk-Operation per Fan-out an die besitzenden Nodes verteilen

Fragen Sie einen verteilten Store nach einem Key, wird der Aufwand von einer einzigen Zahl dominiert: dem Round-Trip zum Node, der ihn besitzt. Der Lookup selbst dauert Nanosekunden; das Netzwerk Mikrosekunden. Fragen Sie nun nach tausend Keys. Wenn Sie in einer Schleife tausendmal Get aufrufen, zahlen Sie diesen Round-Trip tausendmal, seriell, und der Store verbringt fast die gesamte Wanduhrzeit untätig mit dem Warten auf Pakete. Die Keys könnten auf vier Nodes verteilt sein, die parallel hätten antworten können — aber eine naive Schleife gibt ihnen nie die Chance.

Zaris hat drei Bulk-APIs — GetManyAsync, PutManyAsync, DeleteManyAsync — und darunter ein gemischtes ExecuteBatchAsync, und ihr ganzer Daseinszweck ist, „tausend Keys" in „eine Anfrage pro besitzendem Node, parallel abgesetzt" zu verwandeln. Dieser Beitrag ist der Fan-out-Pfad von Anfang bis Ende: wie der Client Keys nach Owner in Buckets sortiert, warum alle vier APIs auf eine einzige Engine zusammenfallen, wie ein Index-Feld die Antworten durch zwei Schichten von Nebenläufigkeit in Reihenfolge hält und warum — anders als bei einer Multi-Key-Transaktion — eine Bulk-Operation pro Item arbeitet und ein Teilerfolg normal ist.

Ein Hop zum Owner: Wie der Zaris-Client einen Key routet

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

Wie der Zaris-Client einen Key zu seinem Owner routet

Es gibt zwei ehrliche Wege, einen Client für einen verteilten Cache zu bauen. Der erste: irgendeinen Node wählen, ihm die Anfrage senden und den Cluster sie intern an den Besitzer des Keys weiterleiten lassen — einfach für den Client, aber jede Anfrage, die auf dem falschen Node landet, zahlt für einen zusätzlichen Netzwerk-Hop innerhalb des Clusters. Der zweite: den Client klug genug machen, um zu wissen, welcher Node den Key besitzt, bevor er irgendetwas sendet, sodass der erste Socket, den er berührt, derjenige ist, der tatsächlich antworten kann. Zaris geht den zweiten Weg. Ein GET verlässt Ihren Prozess bereits an den Node adressiert, der den Key hält — kein Proxy, kein Weiterleitungs-Hop, kein Koordinator in der Mitte.

Dieser Beitrag ist der Blick ins Innere, wie das funktioniert: die Funktion, die einen Key in einen Owner verwandelt, die Lookup-Tabelle, die der Client im Speicher hält, und — der Teil, den man leicht falsch macht — wie der Client korrekt bleibt, wenn sich das Ownership bewegt, während Ihr Traffic unterwegs ist.

Ein Owner, der neu startet, hat kein Recht auf seine eigene Leere

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

Einen neu gestarteten Owner aus seinen Replicas wiederaufbauen

Ein Failover deckt den Moment ab, in dem ein Owner stirbt: Der Cluster wählt einen Überlebenden und bedient weiter. Eine geplante Migration deckt das absichtliche Verschieben der Partition eines gesunden Owners ab. Dieser Beitrag handelt vom dritten Akt, dem, der nach dem Ende der Sirenen abläuft — der ursprüngliche Owner-Prozess startet neu, tritt dem Cluster wieder bei und will seine Partition zurück. Sein Store, der nichts auf der Platte und alles im Speicher hält, kam leer zurück. Die Daten, für die er verantwortlich ist, leben noch, aber auf den Replicas, die weiter bedient haben, während er ausgefallen war.

Das gesamte Korrektheitsproblem steckt in einem Satz: Dem neu gestarteten Owner darf nicht erlaubt werden, seiner eigenen Leere zu trauen. Ein leerer Store sieht genau so aus wie ein Store, den jemand bewusst geleert hat. Nimmt der Node an „ich bin der Owner und habe keine Daten, also ist diese Partition leer", wird er bereitwillig NotFound für Millionen lebender Keys ausliefern und, schlimmer, seinen leeren Zustand zurück auf die Replicas fließen lassen und sie löschen. Dieser Beitrag geht die fünf kleinen, reinen Policies durch, mit denen Zaris sicherstellt, dass das nie geschieht.

Wie ein Zaris-Cluster hochfährt: Mitgliedschaft, die Map und durch Konvergenz gesteuerte Readiness

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

Wie ein Zaris-Cluster hochfährt: Mitgliedschaft, die Map und durch Konvergenz gesteuerte Readiness

Die meisten Texte über verteilte Stores handeln vom Normalbetrieb — Lesen, Schreiben, Replikation — oder von den dramatischen Ausfällen: einem Failover, wenn ein Owner stirbt, oder einem Cut-over, wenn eine Partition umzieht. Doch es gibt einen leiseren Moment, der darüber entscheidet, ob all das funktioniert: der Moment, in dem der Cluster hochfährt. Bevor auch nur ein Key geroutet werden kann, müssen sich die Nodes einigen, wer zum Cluster gehört, wem welcher Ausschnitt des Keyspace gehört und — der Schritt, den die meisten Systeme falsch machen — ob es überhaupt sicher ist, mit dem Bedienen zu beginnen.

Dieser Beitrag folgt dieser Boot-Sequenz in der Reihenfolge, in der Zaris sie tatsächlich ausführt: Mitgliedschaft, Partition-Map und die Readiness-Gates, die zwischen „der Prozess läuft" und „der Node nimmt Traffic an" stehen. Außerdem ziehen wir ehrlich eine Grenze zwischen dem, was Zaris selbst implementiert, und dem, was es von der zugrunde liegenden Cluster-Laufzeit erbt, auf der es aufbaut.

Zwei Cluster, ein Change Feed: Replikation über ein WAN, ohne Zaris zu strecken

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

Zwei unabhängige Cluster, verbunden durch einen wiederaufnehmbaren Change Feed über ein WAN

Früher oder später stellt jemand die Frage: Wir haben einen Cluster in einer Region und Nutzer in einer anderen — können wir nicht einfach dort ein paar Nodes hinzufügen und einen Cluster beide Regionen umspannen lassen? Das ist ein nachvollziehbarer Instinkt. Ein Cluster, ein Namespace, ein Connection-String, Daten überall. Der Instinkt ist aber auch eine Falle, und es lohnt sich, genau zu erklären, warum.

Ein Zaris-Cluster ist für ein Datacenter-Netzwerk konstruiert. Die Mitgliedschaft wird mit Heartbeats auf kurzen Timern verfolgt. Das Ownership einer Partition wechselt zwischen Nodes über einen Handshake, der voraussetzt, dass die Gegenseite schnell antwortet. Das Failover fenced einen vermutlich toten Owner und befördert eine Replica im Sekundenbereich. Jeder dieser Mechanismen ist für eine Verbindung kalibriert, bei der die Round-Trip-Zeit in Mikrosekunden gemessen wird und ein „langsamer" Node tatsächlich krank ist — nicht bloß achtzig Millisekunden und einen Ozean entfernt. Setzt man die Hälfte der Nodes über ein WAN, hat man keinen georedundanten Cluster gebaut, sondern einen Cluster, der normale WAN-Latenz nun für einen Ausfall hält, das Ownership flattern lässt und beim ersten Aussetzer der Verbindung zwischen den Regionen ein Split-Brain riskiert.

Die richtige Form ist also nicht ein gestreckter Cluster. Es sind zwei unabhängige Cluster — jeder in sich geschlossen, mit eigenem Ownership und Failover, das vollständig im eigenen LAN bleibt —, verbunden durch einen asynchronen, wiederaufnehmbaren Change Feed. Dieser Beitrag handelt von diesem Muster: warum Unabhängigkeit die tragende Entscheidung ist und wie das Operation-Log von Zaris Ihnen bereits das Eine liefert, was ein WAN-Replikator tatsächlich braucht — einen Cursor, von dem aus Sie fortsetzen können.

Eine Partition ohne Datenverlust migrieren: das Cut-over-Protokoll

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

Das Zaris-Partition-Cut-over-Protokoll

Ein Failover ist das, was passiert, wenn ein Owner stirbt — der Cluster hat Sekunden, um einen Überlebenden zu wählen, und die Partition-Map bewegt sich nie. Migration ist der ruhigere, gefährlichere Cousin: Der Owner ist völlig gesund, und Sie wollen eine Partition absichtlich von ihm wegbewegen — um den Cluster zu vergrößern, neu zu balancieren oder einen Node zu leeren, den Sie außer Dienst stellen wollen. Nichts ist ausgefallen, und genau deshalb liegt die Latte höher. Ein Failover darf im schlimmsten Fall einige ehrlich verlorene Schreibzugriffe am Ende in Kauf nehmen; eine geplante Migration nicht. Wenn das Verschieben einer Partition von Node A zu Node B einen einzigen bestätigten Schreibzugriff verlieren kann, ist Migration kein Feature, sondern eine Belastung.

Dieser Beitrag geht das Cut-over-Protokoll durch, das Zaris tatsächlich ausführt, in dieser Reihenfolge, und verbringt die meiste Zeit bei dem einen Schritt, den alle falsch machen: dem Moment, in dem die Quelle schließlich „frei" ist, ihre Kopie zu verwerfen. Dieser Schritt ist eine geladene Waffe, und das Interessante an der Ingenieursarbeit ist die Sicherung daran.

Einen Keyspace scannen, der nicht stillhält: Wie SCAN einen Cluster durchläuft

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

Viele sortierte Segmente, zusammengeführt zu einem geordneten, seitenweisen Strom

Ein einzelnes GET auf einen Key ist leicht zu durchdenken: den Key hashen, den Owner finden, genau diesen einen Node fragen. SCAN ist die gegenteilige Art von Operation. Es hat keinen Key — es stellt eine Frage über den gesamten Keyspace: Gib mir jeden Key in diesem Bereich, Seite für Seite. Und in einem partitionierten, replizierten Store ist dieser Keyspace nicht eine Sache an einem Ort. Er ist über 256 Segmente verteilt, die auf so viele Nodes entfallen, wie Sie betreiben, wobei jeder Node nur die Ausschnitte hält, die er gerade besitzt, und während Sie iterieren, wird in die Gesamtheit geschrieben. Es gibt keinen globalen sortierten Index zum Durchlaufen. Woher kommt also die Ordnung, worauf zeigt ein Resume-Token genau, und was passiert mit Ihrem Scan, wenn mittendrin ein Key geschrieben wird — oder eine Partition umzieht?

Dieser Beitrag folgt einem SCAN durch die drei Schichten, die ihn tatsächlich bedienen: ein einzelnes Segment, ein einzelner Node und der Client, der die Nodes zusammenfügt. Jede Schicht löst ein Teilstück des Problems, und die ehrlichen Grenzen der Operation ergeben sich daraus, wie diese Teile zusammenpassen.

Was über die Leitung geht: Die Anatomie eines Zaris-Records

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

Die Anatomie eines gespeicherten Zaris-Records

Das meiste von dem, was Zaris gut macht — einen Schreibzugriff auf ein Backup replizieren, eine hinterherhinkende Replica aufholen lassen, eine Partition auf einen neuen Owner umschalten —, läuft auf eine stille Frage hinaus: Was genau ist die Dateneinheit, die zwischen Nodes wandert? Stimmt diese Einheit, ist Konvergenz fast langweilig. Lässt sie ein Feld weg oder trägt das falsche, bekommen Sie einen wiederauferstandenen gelöschten Key, eine Replica, die Veraltetes nicht von Frischem unterscheiden kann, oder die Buchführung eines Nodes sickert auf einen anderen.

In Zaris ist diese Einheit ein einziger Typ — StoredRecord — und es lohnt sich, ihn Feld für Feld auseinanderzunehmen, denn jede Entscheidung darin ist tragend. Dieser Beitrag ist die Anatomie: was im Record steckt, wie er auf der Leitung gerahmt wird, warum ein Löschvorgang als Record statt als Abwesenheit reist, warum es zwei verschiedene Versionsnummern gibt und — genauso wichtig — was bewusst auf jedem Node zurückbleibt und die Leitung nie überquert.

Anatomie eines Failovers: Was mit einem laufenden Schreibvorgang geschieht, wenn der Owner stirbt

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

Anatomie eines Failovers in Zaris

Ein Failover ist der Moment, in dem ein verteilter Store am ehrlichsten zeigt, was er wirklich ist. Im Normalbetrieb sehen alle Stores gleich aus: Ein Schreibvorgang landet auf einem Owner, wird bestätigt, weiter geht's. Das Design zeigt sich erst, wenn der Owner mitten im Satz verschwindet — ein Node hält die aktive Kopie einer Ihrer Partitionen, Schreibvorgänge landen gerade auf ihm, und dann ist er weg. Hart beendet. Netzwerkpartitioniert. OOM. Der Cluster hat ein paar Sekunden, um das zu bemerken, sich auf einen neuen Owner zu einigen und den Verkehr wieder fließen zu lassen — und ob er das korrekt tut, entscheidet darüber, ob Ihr bestätigter Schreibvorgang überlebt oder stillschweigend verdunstet.

Dieser Beitrag folgt dieser Abfolge von Anfang bis Ende, in der Reihenfolge, in der Zaris sie tatsächlich ausführt, und benennt die Fälle, in denen die Antwort wirklich „der Schreibvorgang ist verloren" lautet — denn ein Failover-Beitrag, der nur den Happy Path beschreibt, ist nicht lesenswert.

Die eigenen Schreibvorgänge lesen: Das Zaris-Konsistenzmodell, ehrlich dargestellt

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

Die eigenen Schreibvorgänge lesen — ein Owner pro Partition

Es gibt eine Frage, die jeder Entwickler irgendwann an einen verteilten Store richtet, meist direkt nach einem verwirrenden Bug-Report: Wenn ich einen Wert schreibe und ihn sofort zurücklese, sehe ich dann garantiert, was ich geschrieben habe? Das klingt, als müsste es eine Ein-Wort-Antwort geben. Gibt es nicht — nicht für irgendeinen partitionierten, replizierten Store, und nicht für Zaris. Die ehrliche Antwort lautet „ja, innerhalb einer Partition, weil Lesevorgänge zum selben einzelnen Owner gehen wie Ihr Schreibvorgang" — und das Interessante ist alles, was in dieser Einschränkung steckt.

Dieser Beitrag ist das Konsistenzmodell von Zaris an einem Ort zusammengetragen. Über die Einzelteile haben wir separat geschrieben — optimistisches Compare-and-Swap, transparenter Retry bei Ownership-Churn, das wiederabspielbare Op-Log, das Replikate speist, Multi-Key-Transaktionen. Hier verbinden wir sie aus Sicht des Lesers und beantworten die einzige Frage, die an der Tastatur zählt: Was wird mir beim Lesen tatsächlich zugesichert? Einschließlich, und vor allem, wo die Zusicherung endet.