Notre expérience de migration Cassandra entre les clusters Kubernetes sans perte de données



Au cours des ~ six derniers mois, nous avons utilisé l' opérateur Rook pour travailler avec Cassandra à Kubernetes . Cependant, lorsque nous avions besoin d'effectuer une opération très banale, il semblerait, opération: changer les paramètres dans la config Cassandra, il s'est avéré que l'opérateur ne fournissait pas une flexibilité suffisante. Pour apporter des modifications, il était nécessaire de cloner le référentiel, d'apporter des modifications aux sources et de reconstruire l'opérateur (la configuration est intégrée à l'opérateur lui-même, donc la connaissance de Go est toujours utile). Tout cela prend beaucoup de temps.

Nous avons déjà fait une revue des opérateurs existants , et cette fois nous nous sommes arrêtés chez CassKop d'Orange , qui prend en charge les fonctionnalités nécessaires, en particulier, les configurations personnalisées et la surveillance prête à l' emploi .

Tâche


Dans la réalité, qui sera discutée plus loin, il a été décidé de combiner le changement d'opérateur avec le besoin urgent de transférer l'ensemble de l'infrastructure client vers le nouveau cluster. Après la migration des principales charges de travail à partir d'applications importantes, seule Cassandra est restée, la perte de données pour laquelle, bien sûr, était inacceptable.

Conditions pour sa migration:

  • Le temps d'inactivitĂ© maximal est de 2 Ă  3 minutes pour effectuer ce transfert en mĂŞme temps que l'application elle-mĂŞme est transfĂ©rĂ©e vers un nouveau cluster;
  • TransfĂ©rez toutes les donnĂ©es sans perte ni mal de tĂŞte (c'est-Ă -dire sans aucune manipulation supplĂ©mentaire).

Comment réaliser une telle opération? Par analogie avec RabbitMQ et MongoDB , nous avons décidé de lancer une nouvelle installation de Cassandra dans un nouveau cluster Kubernetes, puis de fusionner les deux Cassandra dans des clusters différents et de transférer les données, mettant fin à l'ensemble du processus en désactivant simplement l'installation d'origine.

Cependant, cela était compliqué par le fait que les réseaux à l'intérieur de Kubernetes se croisent, il n'était donc pas si facile de configurer la connexion. Il était nécessaire d'enregistrer les itinéraires pour chaque pod sur chaque nœud, ce qui prend beaucoup de temps et n'est pas fiable du tout. Le fait est que la communication sur les pods IP ne fonctionne qu'avec des maîtres, et Cassandra s'exécute sur des nœuds dédiés. Ainsi, vous devez d'abord configurer la route vers le maître et déjà sur le maître - vers un autre cluster. En plus de cela, le redémarrage du pod entraîne un changement d'IP, et c'est un autre problème ... Pourquoi? Lisez à ce sujet plus tard dans l'article.

Dans la partie pratique suivante de l'article, trois notations pour les clusters Cassandra seront utilisées:

  • Cassandra-new - la nouvelle installation que nous lancerons dans le nouveau cluster Kubernetes;
  • Cassandra-current - une ancienne installation avec laquelle les applications fonctionnent actuellement;
  • Cassandra-temporaire est une installation temporaire que nous exĂ©cutons Ă  cĂ´tĂ© de Cassandra-current et nous l'utilisons uniquement pour le processus de migration lui-mĂŞme.

Comment ĂŞtre?


Étant donné que Cassandra-current utilise le stockage local, une simple migration de ses données vers un nouveau cluster - cela pourrait être, par exemple, dans le cas des disques vSphere ... - est impossible. Pour résoudre ce problème, nous allons créer un cluster temporaire, en l'utilisant comme une sorte de tampon pour la migration.

La séquence générale des actions est réduite aux étapes suivantes:

  1. Élevez Cassandra-new avec un nouvel opérateur dans un nouveau cluster.
  2. Échelle à 0 nouveau cluster Cassandra .
  3. , PVC, .
  4. Cassandra-temporary Cassandra-current , Cassandra-new.
  5. Cassandra-temporary 0 ( ) Cassandra-temporary , Cassandra-temporary Cassandra-current. Cassandra - ( Cassandra ).
  6. Transférez des données entre les centres de données Cassandra-temporaire et Cassandra-actuel .
  7. Mettez à l'échelle les clusters Cassandra-courant et Cassandra-temporaire à 0 et exécutez Cassandra-new dans le nouveau cluster, sans oublier de jeter les disques. En parallèle, nous déployons les applications vers un nouveau cluster.

Ă€ la suite de telles manipulations, les temps d'arrĂŞt seront minimes.

En détail


Avec les 3 premières étapes, il ne devrait y avoir aucun problème - tout se fait rapidement et facilement.

Ă€ ce stade, le cluster Cassandra-actuel ressemblera Ă  ceci:

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

Pour vérifier que tout fonctionne comme prévu, créez un espace de clés dans Cassandra-current . Cela se fait avant le lancement de Cassandra-temporaire :

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

Ensuite, créez un tableau et remplissez-le de données:

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);

Exécutez Cassandra-temporaire , en vous rappelant qu'avant cela, dans le nouveau cluster, nous avons déjà démarré Cassandra-new (étape # 1) et maintenant il est désactivé (étape # 2).

Remarques:

  1. Lorsque nous démarrons Cassandra-temporaire , nous devons spécifier le même nom (avec Cassandra-current ) du cluster. Cela peut être fait via une variable CASSANDRA_CLUSTER_NAME.
  2. Pour que Cassandra-temporaire puisse voir le cluster actuel, vous devez définir les graines. Cela se fait via une variable CASSANDRA_SEEDSou via une configuration.

Attention! Avant de commencer à déplacer des données, vous devez vous assurer que les types de cohérence en lecture et en écriture sont définis sur LOCAL_ONEou LOCAL_QUORUM.

Après le démarrage temporaire de Cassandra , le cluster devrait ressembler à ceci (notez l'apparition d'un deuxième centre de données avec 3 nœuds):

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

Vous pouvez maintenant effectuer le transfert. Pour ce faire, transférez d'abord l'espace de touches de test - assurez-vous que tout va bien:

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


Après cela, dans chaque module Cassandra temporaire , exécutez la commande:

nodetool rebuild -ks example x1

Passons à n'importe quel pod de Cassandra-temporaire et vérifions que les données ont été transférées. Vous pouvez également ajouter 1 entrée supplémentaire à Cassandra-current pour vérifier que les nouvelles données ont commencé à se répliquer:

SELECT * FROM example;

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

(3 rows)

Après cela, vous pouvez faire ALTERtous les espaces clés dans Cassandra-current et l'exécuter nodetool rebuild.

Manque d'espace et de mémoire


À ce stade, il est utile de se rappeler que lorsque la reconstruction est en cours d'exécution, des fichiers temporaires sont créés dont la taille est équivalente à la taille de l'espace clé! Nous avons rencontré un problème selon lequel le plus grand espace de clés était de 350 Go et l'espace disque disponible était moindre.

Il n'a pas été possible d'étendre le disque, car le stockage local est utilisé. La commande suivante est venue à la rescousse (exécutée dans chaque pod de Cassandra-current ):

nodetool clearsnapshot

L'endroit a donc été libéré: dans notre cas, 500 Go d'espace disque libre ont été obtenus au lieu des 200 Go précédemment disponibles.

Cependant, malgré le manque d'espace, l'opération de reconstruction a constamment provoqué le redémarrage des pods Cassandra temporaires avec une erreur:

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

Nous l'avons décidé en créant DaemonSet, qui se déploie uniquement sur les nœuds avec Cassandra-temporaire et effectue:

sysctl -w vm.max_map_count=262144

Enfin, toutes les données ont été migrées!

Commutation de cluster


Il ne restait plus qu'à changer la Cassandra, qui s'est déroulée en 5 étapes:

  1. Échelle Cassandra-temporaire et Cassandra-courant (n'oubliez pas que l'opérateur fonctionne toujours ici!) À 0.
  2. Commutez les disques (cela revient à régler PV pour Cassandra-new ).
  3. Nous démarrons Cassandra-new , en vérifiant que les disques nécessaires sont connectés.
  4. Nous faisons ALTERtoutes les tables pour supprimer l'ancien cluster:

    ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', 'x2': 2};
  5. Supprimez tous les nœuds de l'ancien cluster. Pour ce faire, exécutez simplement cette commande dans l'un de ses modules:

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

Le temps d'arrêt total de Cassandra était d'environ 3 minutes - c'est le moment où les conteneurs se sont arrêtés et ont démarré, car les disques ont été préparés à l'avance.

Touche finale avec Prometheus


Mais cela ne s'arrête pas là. Il existe un exportateur intégré avec Cassandra-new (voir la documentation du nouvel opérateur ) - nous l'avons bien sûr utilisé. Environ 1 heure après le lancement, des alertes concernant l'inaccessibilité de Prometheus ont commencé à arriver. Après avoir vérifié la charge, nous avons vu que la consommation de mémoire sur les nœuds avec Prometheus a augmenté.

Une étude plus approfondie de la question a montré que le nombre de mesures collectées a augmenté de 2,5 fois (!). La faute était Cassandra, avec laquelle un peu plus de 500 000 mesures ont été collectées.

Nous avons effectué un audit des métriques et désactivé celles que nous n'avons pas jugées nécessaires - via ConfigMap (en l'occurrence, l'exportateur est configuré). Le résultat est 120 000 métriques et une charge significativement réduite sur Prometheus (malgré le fait que des métriques importantes restent).

Conclusion


Nous avons donc réussi à transférer Cassandra vers un autre cluster, pratiquement sans affecter le fonctionnement de l'installation de production de Cassandra et sans interférer avec le travail des applications clientes. En cours de route, nous sommes arrivés à la conclusion que l'utilisation du même réseau de pods n'est pas une bonne idée (nous sommes maintenant plus attentifs à la planification initiale de l'installation du cluster).

Enfin: pourquoi n'avons-nous pas utilisé l'outil nodetool snapshotmentionné dans l'article précédent? Le fait est que cette commande crée un instantané d'espace de clés dans l'état où elle se trouvait avant l'exécution de la commande. Outre:

  • il faut beaucoup plus de temps pour prendre une photo et la transfĂ©rer;
  • tout ce qui est Ă©crit en ce moment Ă  Cassandra sera perdu;
  • simple dans notre cas serait d'environ une heure - au lieu de 3 minutes, ce qui s'est avĂ©rĂ© ĂŞtre combinĂ© avec succès avec le dĂ©ploiement de l'application sur un nouveau cluster.

PS


Lisez aussi dans notre blog:


All Articles