Slot-Migrationsübersicht
In Garnet beschreibt die Slot-Migration den Prozess der Neuzuweisung von Slot-Besitzern und der Übertragung der zugehörigen Schlüssel-Wert-Paare von einem primären Knoten zu einem anderen innerhalb eines voll betriebsbereiten Clusters. Dieser Vorgang ermöglicht eine effiziente Ressourcennutzung und Lastverteilung im Cluster, wenn Knoten hinzugefügt oder entfernt werden. Der Migrationsvorgang ist nur im Cluster-Modus verfügbar. Die Slot-Migration kann vom Besitzer (dem sogenannten Quellknoten) eines bestimmten Slots initiiert und an einen anderen, bereits bekannten und vertrauenswürdigen primären Knoten (den sogenannten Zielknoten) gerichtet werden. Die eigentliche Datenmigration kann mit dem Befehl MIGRATE initiiert werden, der in zwei Modi operiert: (1) Einzelne Schlüssel migrieren (2) Gesamte Slots oder Slot-Bereiche migrieren. Diese Seite konzentriert sich auf die Implementierungsdetails der Slot-Migration. Weitere Informationen zur Verwendung des zugehörigen Befehls finden Sie im Benutzerhandbuch zur Slot-Migration.
Implementierungsdetails
Die Implementierung des Migrationsvorgangs ist in zwei Komponenten unterteilt
- Befehlsparcing- und Validierungskomponente.
- Migrationssitzungsbetriebs- und Verwaltungskomponente.
Die erste Komponente ist für das Parsen und Validieren der Migrationsbefehlsargumente zuständig. Die Validierung umfasst Folgendes
- Alle Migrationsoptionen parsen und die mit jeder Option verbundenen Argumente validieren.
- Den Besitz des zu migrierenden Slots validieren.
- Für die Option
KEYSvalidieren, dass die zu migrierenden Schlüssel nicht über verschiedene Slots gehasht werden. - Für die Option
SLOTS/SLOTSRANGEvalidieren, dass kein Slot mehrfach referenziert wird. - Für die Option
SLOTSRANGEsicherstellen, dass ein Bereich durch ein Wertepaar definiert ist. - Validieren, dass das Ziel der Migration bekannt, vertrauenswürdig ist und die Rolle eines Primärknotens innehat.
Wenn das Parsen erfolgreich abgeschlossen ist, wird eine Migrationssitzung erstellt und ausgeführt. Abhängig von der gewählten Option wird die Migrationssitzung entweder als Vordergrundaufgabe (mit der Option KEYS) oder als Hintergrundaufgabe (Option SLOTS/SLOTSRANGE) ausgeführt.
Die zweite Komponente ist in folgende Unterkomponenten unterteilt
MigrationManagerMigrateSessionTaskStoreMigrateSession
Der MigrationManager ist für die Verwaltung der aktiven MigrateSession-Aufgaben verantwortlich. Er verwendet den MigrateSessionTaskStore, um neue Instanzen von MigrateSession atomar hinzuzufügen oder zu entfernen. Er ist auch dafür verantwortlich, sicherzustellen, dass bestehende Sitzungen nicht mit neu hinzuzufügenden Sitzungen kollidieren, indem er prüft, ob die in jeder Sitzung referenzierten Slots nicht kollidieren. Schließlich liefert er Informationen über die Anzahl der laufenden Migrationsaufgaben.
Datenintegrität bei Migrationen
Da die Slot-Migration initiiert werden kann, während ein Garnet-Cluster in Betrieb ist, muss sie sorgfältig orchestriert werden, um Datenintegritätsprobleme zu vermeiden, wenn Clients versuchen, neue Daten zu schreiben. Darüber hinaus sollte keine Lösung die Datenverfügbarkeit während der Migration beeinträchtigen.
Unsere Implementierung nutzt das Konzept der Slot-basierten Sharding, um sicherzustellen, dass Schlüssel, die zugehörigen Slots zugeordnet sind, während einer aktiven Migrationsaufgabe nicht geändert werden können. Dies wird erreicht, indem der Slot-Status auf dem Quellknoten auf MIGRATING gesetzt wird. Dies verhindert Schreibvorgänge, erlaubt aber weiterhin Lesezugriffe. Schreibvorgänge können mit ASKING an den Zielknoten gesendet werden, es gibt jedoch keine Konsistenzgarantien von Garnet, wenn diese Option verwendet wird. Garnet garantiert, dass während der normalen Migration (d.h. mit ASKING) keine Schlüssel verloren gehen.
Da Garnet in einer Multi-Thread-Umgebung arbeitet, muss der Übergang von STABLE zu MIGRATING sicher erfolgen, damit jeder Thread die Möglichkeit hat, diese Zustandsänderung zu beobachten. Dies kann durch Epoch-Schutz erreicht werden. Insbesondere, wenn ein Slot in einen neuen Zustand übergeht, muss das Segment, das die tatsächliche Zustandsänderung implementiert, nach der Änderung einen Spin-Wait durchführen und erst zurückkehren, nachdem alle aktiven Clientsitzungen zur nächsten Epoch übergegangen sind.
Ein Auszug aus dem Code, der sich auf den Epoch-Schutz während des Slot-Zustandsübergangs bezieht, ist unten dargestellt. Jede Clientsitzung holt sich vor der Verarbeitung eines eingehenden Pakets die aktuelle Epoch. Dies geschieht auch für die Clientsitzung, die einen Slot-Zustandsübergangs-Befehl ausgibt (z.B. CLUSTER SETSLOT). Nach erfolgreicher Aktualisierung des lokalen Konfigurationsbefehls führt der Verarbeitungsthread des vorherigen Befehls Folgendes aus:
- die aktuelle Epoch freigeben (um zu vermeiden, dass auf sich selbst gewartet wird).
- Spin-Wait, bis alle Threads zur nächsten Epoch übergegangen sind.
- die nächste Epoch erneut anfordern.
Diese Schrittesequenz stellt sicher, dass der Verarbeitungsthread bei der Rückgabe dem Befehlsgeber (oder dem Methodenaufrufer, falls die Zustandsänderung intern erfolgt) garantiert, dass die Zustandsänderung für alle aktiven Threads sichtbar ist. Daher wird jede aktive Clientsitzung nachfolgende Befehle unter Berücksichtigung des neuen Slot-Status verarbeiten.
loading...
Während der Migration ist die Änderung des Slot-Status (d.h. MIGRATING) aus Sicht des Quellknotens transient. Das bedeutet, dass der Slot bis zum Abschluss der Migration immer noch vom Quellknoten besessen wird. Da jedoch die Erzeugung von -ASK-Umleitungsnachrichten erforderlich ist, wird die workerId auf die workerId des Zielknotens gesetzt, ohne die aktuelle lokale Epoch zu inkrementieren (um die Weitergabe dieser transienten Aktualisierung an den gesamten Cluster zu vermeiden). Je nach Kontext der ausgeführten Operation kann der tatsächliche Besitzer des Knotens durch Zugriff auf die workerId-Eigenschaft bestimmt werden, während der Zielknoten für die Migration über die _workerId-Variable bestimmt wird. Beispielsweise verwendet CLUSTER NODES die workerId-Eigenschaft (über GetSlotRange(workerId)), da es den tatsächlichen Besitzer des Knotens auch während der Migration zurückgeben muss. Gleichzeitig muss es alle Knoten zurückgeben, die sich im Zustand MIGRATING oder IMPORTING befinden, sowie die mit diesem Zustand verbundene Node-ID, was durch Inspektion der _workerId-Variable (über GetSpecialStates(workerId)) erfolgen kann.
loading...
Details zur Implementierung von Migrate KEYS
Mit der Option KEYS iteriert Garnet durch die bereitgestellte Liste von Schlüsseln und migriert sie in Batches zum Zielknoten. Bei Verwendung dieser Option muss der Ausgeber des Migrationsbefehls sicherstellen, dass der Slot-Status auf dem Quell- und Zielknoten entsprechend gesetzt ist. Darüber hinaus muss der Ausgeber alle Schlüssel bereitstellen, die zu einem bestimmten Slot gehören, entweder in einem Aufruf von MIGRATE oder über mehrere Aufrufe, bevor die Migration abgeschlossen ist. Wenn alle Schlüssel-Wert-Paare zum Zielknoten migriert wurden, muss der Ausgeber den Slot-Status zurücksetzen und den Besitz des Slots dem neuen Knoten zuweisen.
MigrateKeys ist der Haupttreiber für den Migrationsvorgang mit der Option KEYS. Diese Methode iteriert über die Liste der bereitgestellten Schlüssel und sendet sie an den Zielknoten. Dies geschieht in den folgenden zwei Phasen
- Alle vom
MIGRATE-Befehl bereitgestellten Schlüssel finden und an den Zielknoten senden. - Für alle verbleibenden Schlüssel, die nicht im Hauptspeicher gefunden wurden, im Objektspeicher nachschlagen, und wenn sie gefunden werden, an den Zielknoten senden. Es ist möglich, dass ein bestimmter Schlüssel aus keinem der Speicher abgerufen werden kann, da er abgelaufen sein könnte. In diesem Fall wird die Ausführung mit dem nächsten verfügbaren Schlüssel fortgesetzt und kein spezifischer Fehler gemeldet. Wenn die Datenübertragung abgeschlossen ist und je nachdem, ob die COPY-Option aktiviert ist, löscht
MigrateKeysdie Schlüssel aus beiden Speichern.
loading...
Details zu Migrate SLOTS
Die Optionen SLOTS oder SLOTSRANGE ermöglichen es Garnet, eine Sammlung von Slots und alle zugehörigen Schlüssel, die zu diesen Slots gehören, zu migrieren. Diese Optionen unterscheiden sich von den KEYS-Optionen in den folgenden Punkten
- Es ist nicht notwendig, spezifische Kenntnisse über die einzelnen zu migrierenden Schlüssel und deren Zuordnung zu den zugehörigen Slots zu haben. Der Benutzer muss lediglich eine Slot-Nummer angeben.
- Zustandsübergänge werden vollständig serverseitig gehandhabt.
- Damit der Migrationsvorgang abgeschlossen werden kann, müssen sowohl der Haupt- als auch der Objektspeicher gescannt werden, um alle dem angegebenen Slot zugeordneten Schlüssel zu finden und zu migrieren.
Es mag angesichts des letzten Punktes oben den Anschein erwecken, dass der Migrationsvorgang mit SLOTS oder SLOTSRANGE teurer ist, insbesondere wenn der zu migrierende Slot nur wenige Schlüssel enthält. Er ist jedoch im Allgemeinen weniger teuer als die Option KEYS, die mehrere Roundtrips zwischen Client und Server erfordert (damit relevante Schlüssel als Eingabe für den Befehl MIGRATE verwendet werden können) und zusätzlich einen vollständigen Scan beider Speicher durchführen muss.
Wie im untenstehenden Codeausschnitt gezeigt, übergibt die MIGRATE SLOTS-Aufgabe den Zustand eines Slots in der Konfiguration des Remote-Knotens sicher auf IMPORTING und den Zustand des lokalen Knotens auf MIGRATING, indem sie auf den zuvor beschriebenen Epoch-Schutzmechanismus zurückgreift. Anschließend beginnt sie mit der Migration der Daten in Batches zum Zielknoten. Nach Abschluss der Datenmigration endet die Aufgabe mit der Durchführung des nächsten Slot-Zustandsübergangs, bei dem der Besitz der migrierten Slots an den Zielknoten übergeben wird. Der Austausch des Slot-Besitzes wird durch Erhöhung der Konfigurations-Epoch des lokalen Knotens (d.h. mithilfe des RelinquishOwnership-Befehls) im gesamten Cluster sichtbar. Abschließend sendet der Quellknoten CLUSTER SETSLOT NODE an den Zielknoten, um ihn explizit zum Besitzer der entsprechenden Slot-Sammlung zu machen. Dieser letzte Schritt ist nicht zwingend erforderlich und dient lediglich zur Beschleunigung der Konfigurationsweitergabe.
loading...