Unsere Cassandra-Migrationserfahrung zwischen Kubernetes-Clustern ohne Datenverlust



In den letzten sechs Monaten haben wir den Rook-Operator verwendet , um mit Cassandra in Kubernetes zusammenzuarbeiten . Wenn wir jedoch eine sehr triviale Operation ausführen mussten, schien es: Operation: Ändern Sie die Parameter in der Cassandra-Konfiguration. Es stellte sich heraus, dass der Operator keine ausreichende Flexibilität bot. Um Änderungen vorzunehmen, musste das Repository geklont, Änderungen an den Quellen vorgenommen und der Operator neu erstellt werden (die Konfiguration ist in den Operator selbst integriert, sodass Go-Kenntnisse weiterhin nützlich sind). All dies kostet viel Zeit.

Wir haben bereits eine Überprüfung der vorhandenen Betreiber durchgeführt und dieses Mal haben wir bei CassKop von Orange aus angehalten , das die erforderlichen Funktionen unterstützt, insbesondere benutzerdefinierte Konfigurationen und sofort einsatzbereite Überwachung.

Aufgabe


In der realen Geschichte, die später besprochen wird, wurde beschlossen, den Wechsel des Betreibers mit der dringenden Notwendigkeit zu verbinden, die gesamte Client-Infrastruktur auf den neuen Cluster zu übertragen. Nach der Migration der Haupt-Workloads aus wichtigen Anwendungen blieb nur Cassandra übrig, deren Datenverlust natürlich nicht akzeptabel war.

Voraussetzungen für die Migration:

  • Die maximale Leerlaufzeit beträgt 2-3 Minuten, um diese Übertragung tatsächlich durchzuführen, während die Anwendung auf einen neuen Cluster übertragen wird.
  • Übertragen Sie alle Daten ohne Verlust und Kopfschmerzen (d. H. Ohne zusätzliche Manipulationen).

Wie führe ich eine solche Operation durch? In Analogie zu RabbitMQ und MongoDB haben wir beschlossen, eine neue Installation von Cassandra in einem neuen Kubernetes-Cluster zu starten, dann die beiden Cassandra in verschiedenen Clustern zusammenzuführen und die Daten zu übertragen, um den gesamten Prozess durch einfaches Deaktivieren der ursprünglichen Installation zu beenden.

Es wurde jedoch durch die Tatsache erschwert, dass sich die Netzwerke in Kubernetes überschneiden, sodass es nicht so einfach war, die Verbindung zu konfigurieren. Es war erforderlich, Routen für jeden Pod auf jedem Knoten zu registrieren, was sehr zeitaufwändig und überhaupt nicht zuverlässig ist. Tatsache ist, dass die Kommunikation über IP-Pods nur mit Mastern funktioniert und Cassandra auf dedizierten Knoten ausgeführt wird. Daher müssen Sie zuerst die Route zum Master und bereits auf dem Master konfigurieren - zu einem anderen Cluster. Darüber hinaus führt ein Neustart des Pods zu einer Änderung der IP-Adresse. Dies ist ein weiteres Problem ... Warum? Lesen Sie später in diesem Artikel darüber.

Im folgenden praktischen Teil des Artikels werden drei Notationen für Cassandra-Cluster verwendet:

  • Cassandra-new - die neue Installation, die wir im neuen Kubernetes-Cluster starten werden;
  • Cassandra-current - eine alte Installation, mit der derzeit Anwendungen arbeiten;
  • Cassandra-temporär ist eine temporäre Installation, die wir neben Cassandra-current ausführen und nur für den Migrationsprozess selbst verwenden.

Wie soll ich sein?


Da Cassandra-current localstorage verwendet, ist eine einfache Migration seiner Daten in einen neuen Cluster - dies könnte beispielsweise bei vSphere-Festplatten der Fall sein ... - nicht möglich. Um dieses Problem zu lösen, erstellen wir einen temporären Cluster, der als eine Art Puffer für die Migration verwendet wird.

Die allgemeine Abfolge der Aktionen wird auf die folgenden Schritte reduziert:

  1. Erhöhen Sie Cassandra-new mit einem neuen Operator in einem neuen Cluster.
  2. Skaliere auf 0 Cassandra-neuer Cluster .
  3. , PVC, .
  4. Cassandra-temporary Cassandra-current , Cassandra-new.
  5. Cassandra-temporary 0 ( ) Cassandra-temporary , Cassandra-temporary Cassandra-current. Cassandra - ( Cassandra ).
  6. Übertragen von Daten zwischen Cassandra nur vorübergehend und Cassandra Strom Rechenzentren .
  7. Skalieren Sie die Cassandra-aktuellen und Cassandra-temporären Cluster auf 0 und führen Sie Cassandra-new im neuen Cluster aus, ohne zu vergessen, die Festplatten zu werfen. Parallel dazu rollen wir Anwendungen in einen neuen Cluster.

Infolge solcher Manipulationen sind die Ausfallzeiten minimal.

Im Detail


Bei den ersten drei Schritten sollte es keine Probleme geben - alles ist schnell und einfach erledigt.

Zu diesem Zeitpunkt sieht der Cassandra-aktuelle Cluster ungefähr so ​​aus:

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

Um zu überprüfen, ob alles wie erwartet funktioniert, erstellen Sie einen Schlüsselbereich in Cassandra-current . Dies geschieht vor dem Start von Cassandra-temporär :

create keyspace example with replication ={'class' : 'NetworkTopologyStrategy', 'x1':2};

Erstellen Sie als Nächstes eine Tabelle und füllen Sie sie mit Daten:

use example;
CREATE TABLE example(id int PRIMARY KEY, name text, phone varint);
INSERT INTO example(id, name, phone) VALUES(1,'Masha', 983123123);
INSERT INTO example(id, name, phone) VALUES(2,'Sergey', 912121231);
INSERT INTO example(id, name, phone) VALUES(3,'Andrey', 914151617);

Führen Sie Cassandra-temporär aus , und denken Sie daran, dass wir zuvor im neuen Cluster Cassandra-new bereits gestartet haben (Schritt 1) ​​und es jetzt deaktiviert ist (Schritt 2).

Anmerkungen:

  1. Wenn wir Cassandra-temporär starten , müssen wir denselben (mit Cassandra-aktuell ) Namen des Clusters angeben . Dies kann über eine Variable erfolgen CASSANDRA_CLUSTER_NAME.
  2. Damit Cassandra-temporär den aktuellen Cluster sehen kann, müssen Sie die Startwerte festlegen. Dies erfolgt über eine Variable CASSANDRA_SEEDSoder über eine Konfiguration.

Beachtung! Bevor Sie mit dem Verschieben von Daten beginnen, müssen Sie sicherstellen, dass die Lese- und Schreibkonsistenztypen auf LOCAL_ONEoder eingestellt sind LOCAL_QUORUM.

Nach dem temporären Start von Cassandra sollte der Cluster folgendermaßen aussehen (beachten Sie das Erscheinungsbild eines zweiten Rechenzentrums mit 3 Knoten):

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

Datacenter: x2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address       Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.244.16.96  267.07 KiB  256          64.4%             3619841e-64a0-417d-a497-541ec602a996  rack1
UN  10.244.18.67  248.29 KiB  256          65.8%             07a2f571-400c-4728-b6f7-c95c26fe5b11  rack1
UN  10.244.16.95  265.85 KiB  256          69.8%             2f4738a2-68d6-4f9e-bf8f-2e1cfc07f791  rack1

Jetzt können Sie die Übertragung durchführen. Übertragen Sie dazu zuerst den Testschlüsselraum - stellen Sie sicher, dass alles in Ordnung ist:

ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', x1: 2, x2: 2};


Führen Sie danach in jedem temporären Cassandra- Pod den folgenden Befehl aus:

nodetool rebuild -ks example x1

Gehen wir zu einem beliebigen Pod von Cassandra-temporär und überprüfen, ob die Daten übertragen wurden. Sie können Cassandra-current auch einen weiteren Eintrag hinzufügen , um zu überprüfen, ob die Replikation neuer Daten begonnen hat:

SELECT * FROM example;

 id | name   | phone
----+--------+-----------
  1 |  Masha | 983123123
  2 | Sergey | 912121231
  3 | Andrey | 914151617

(3 rows)

Danach können Sie ALTERalle Keyspaces in Cassandra-current ausführen und ausführen nodetool rebuild.

Platz- und Gedächtnismangel


In diesem Stadium ist es hilfreich, sich daran zu erinnern, dass beim Ausführen der Neuerstellung temporäre Dateien erstellt werden, deren Größe der Größe des Schlüsselbereichs entspricht. Wir haben das Problem festgestellt, dass der größte Schlüsselbereich 350 GB betrug und weniger freier Speicherplatz vorhanden war.

Es war nicht möglich, die Festplatte zu erweitern, da localstorage verwendet wird. Der folgende Befehl kam zur Rettung (ausgeführt in jeder Kapsel von Cassandra-current ):

nodetool clearsnapshot

So wurde der Platz frei: In unserem Fall wurden 500 GB freier Speicherplatz anstelle der zuvor verfügbaren 200 GB erhalten.

Trotz der Tatsache, dass genügend Speicherplatz vorhanden war, verursachte der Wiederherstellungsvorgang ständig den Neustart von Cassandra-temporären Pods mit einem Fehler:

failed; error='Cannot allocate memory' (errno=12)

Wir haben uns dafür entschieden, indem wir DaemonSet erstellt haben, das nur für Knoten mit Cassandra-temporär bereitgestellt wird und Folgendes ausführt:

sysctl -w vm.max_map_count=262144

Endlich wurden alle Daten migriert!

Cluster-Switching


Es blieb nur die Cassandra zu wechseln, die in 5 Stufen durchgeführt wurde:

  1. Skalieren Sie Cassandra-temporär und Cassandra-aktuell (vergessen Sie nicht, dass der Operator hier noch arbeitet!) Auf 0.
  2. Switch Disks (es kommt darauf an, PV für Cassandra-new einzustellen ).
  3. Wir starten Cassandra-new und verfolgen, ob die erforderlichen Festplatten angeschlossen sind.
  4. Wir machen ALTERalle Tabellen, um den alten Cluster zu entfernen:

    ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', 'x2': 2};
  5. Löschen Sie alle Knoten des alten Clusters. Führen Sie dazu einfach diesen Befehl in einem der Pods aus:

    nodetool removenode 3619841e-64a0-417d-a497-541ec602a996

Die gesamte Ausfallzeit von Cassandra betrug ca. 3 Minuten - dies ist die Zeit, in der die Container angehalten und gestartet wurden, da die Festplatten im Voraus vorbereitet wurden.

Letzter Schliff mit Prometheus


Dies endete jedoch nicht dort. Es gibt einen eingebauten Exporteur mit Cassandra-new (siehe Dokumentation des neuen Betreibers ) - wir haben ihn natürlich verwendet. Ungefähr eine Stunde nach dem Start kam es zu Warnungen über die Unzugänglichkeit von Prometheus. Nach Überprüfung der Last haben wir festgestellt, dass der Speicherverbrauch auf Knoten mit Prometheus gestiegen ist.

Weitere Untersuchungen des Problems zeigten, dass sich die Anzahl der gesammelten Metriken um das 2,5-fache (!) Erhöhte. Der Fehler war Cassandra, mit der etwas mehr als 500.000 Metriken gesammelt wurden.

Wir haben eine Überprüfung der Metriken durchgeführt und diejenigen deaktiviert, die wir nicht für notwendig erachteten - über ConfigMap (darin ist übrigens der Exporter konfiguriert). Das Ergebnis sind 120.000 Metriken und eine deutlich geringere Belastung von Prometheus (trotz der Tatsache, dass wichtige Metriken erhalten bleiben).

Fazit


So gelang es uns, Cassandra auf einen anderen Cluster zu übertragen, praktisch ohne die Funktionsweise der Produktionsinstallation von Cassandra zu beeinträchtigen und ohne die Arbeit von Clientanwendungen zu beeinträchtigen. Auf dem Weg kamen wir zu dem Schluss, dass die Verwendung desselben Pod-Netzwerks keine gute Idee ist (jetzt achten wir mehr auf die anfängliche Planung für die Installation des Clusters).

Zum Schluss: Warum haben wir das nodetool snapshotim vorherigen Artikel erwähnte Tool nicht verwendet ? Tatsache ist, dass dieser Befehl einen Keyspace-Snapshot in dem Zustand erstellt, in dem er sich vor der Ausführung des Befehls befand. Außerdem:

  • Es dauert viel länger, ein Bild aufzunehmen und es zu übertragen.
  • alles, was zu dieser Zeit in Cassandra geschrieben steht, geht verloren;
  • In unserem Fall wäre dies ungefähr eine Stunde - anstelle von 3 Minuten, was sich als erfolgreich mit der Bereitstellung der Anwendung in einem neuen Cluster kombinierte.

PS


Lesen Sie auch in unserem Blog:


All Articles