Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment reconstruire un esclave MySQL incohérent ?

Les esclaves MySQL peuvent devenir incohérents. Vous pouvez essayer de l'éviter, mais c'est vraiment difficile. Définir super_read_only et utiliser la réplication basée sur les lignes peut aider beaucoup, mais quoi que vous fassiez, il est toujours possible que votre esclave devienne incohérent.

Que peut-on faire pour reconstruire un esclave MySQL incohérent ? Dans cet article de blog, nous examinerons ce problème.

Tout d'abord, discutons de ce qui doit se passer pour reconstruire un esclave. Pour amener un nœud dans la réplication MySQL, il doit être provisionné avec les données de l'un des nœuds de la topologie de réplication. Ces données doivent être cohérentes au moment où elles ont été collectées. Vous ne pouvez pas le prendre table par table ou schéma par schéma, car cela rendrait le nœud provisionné incohérent en interne. Cela signifie que certaines données seraient plus anciennes que d'autres parties de l'ensemble de données.

En plus de la cohérence des données, il devrait également être possible de collecter des informations sur la relation entre les données et l'état de la réplication. Vous souhaitez avoir soit une position de journal binaire à laquelle les données collectées sont cohérentes, soit l'ID de transaction global de la transaction qui a été la dernière exécutée sur le nœud qui est la source des données.

Cela nous amène aux considérations suivantes. Vous pouvez reconstruire un esclave à l'aide de n'importe quel outil de sauvegarde tant que cet outil peut générer une sauvegarde cohérente et qu'il inclut les coordonnées de réplication pour le point dans le temps auquel la sauvegarde est cohérente. Cela nous permet de choisir parmi quelques options.

Utiliser Mysqldump pour reconstruire un esclave MySQL incohérent

Mysqldump est l'outil le plus basique dont nous disposons pour y parvenir. Il nous permet de créer une sauvegarde logique sous, entre autres, la forme d'instructions SQL. Ce qui est important, tout en étant basique, cela nous permet tout de même de faire une sauvegarde cohérente :il peut utiliser transaction pour s'assurer que les données sont cohérentes au début de la transaction. Il peut également écrire les coordonnées de réplication pour ce point, voire une instruction CHANGE MASTER entière, ce qui facilite le démarrage de la réplication à l'aide de la sauvegarde.

Utiliser Mydumper pour reconstruire un esclave MySQL incohérent

Une autre option consiste à utiliser mydumper - cet outil, tout comme mysqldump, génère une sauvegarde logique et, tout comme mysqldump, peut être utilisé pour créer une sauvegarde cohérente de la base de données. La principale différence entre mydumper et mysqldump est que mydumper, lorsqu'il est associé à myloader, peut vider et restaurer des données en parallèle, améliorant ainsi le vidage et, surtout, le temps de restauration.

Utiliser un instantané pour reconstruire un esclave MySQL incohérent

Pour ceux qui utilisent des fournisseurs de cloud, une possibilité consiste à prendre un instantané du stockage de blocs sous-jacent. Les instantanés génèrent une vue ponctuelle des données. Ce processus est cependant assez délicat, car la cohérence des données et la possibilité de les restaurer dépendent principalement de la configuration MySQL.

Vous devez vous assurer que la base de données fonctionne en mode durable (elle est configurée de manière à ce que le crash de MySQL n'entraîne aucune perte de données). C'est parce que (du point de vue de MySQL) prendre un instantané de volume puis démarrer une autre instance MySQL à partir des données qui y sont stockées est, fondamentalement, le même processus que si vous deviez tuer -9 le mysqld puis le redémarrer. La récupération InnoDB doit avoir lieu, rejouer les transactions qui ont été stockées dans des journaux binaires, annuler les transactions qui ne se sont pas terminées avant le crash, etc.

L'inconvénient du processus de reconstruction basé sur un instantané est qu'il est fortement lié au fournisseur actuel. Vous ne pouvez pas facilement copier les données d'instantané d'un fournisseur de cloud vers un autre. Vous pourrez peut-être le déplacer entre différentes régions, mais il s'agira toujours du même fournisseur.

Utiliser un Xtrabackup ou Mariabackup pour reconstruire un esclave MySQL incohérent

Enfin, xtrabackup/mariabackup - c'est un outil écrit par Percona et forké par MariaDB qui permet de générer une sauvegarde physique. C'est beaucoup plus rapide que les sauvegardes logiques - il est principalement limité par les performances matérielles - le disque ou le réseau étant les goulots d'étranglement les plus probables. La majeure partie de la charge de travail est liée à la copie de fichiers du répertoire de données MySQL vers un autre emplacement (sur le même hôte ou sur le réseau).

Bien qu'il ne soit pas aussi rapide que les instantanés de stockage en mode bloc, xtrabackup est bien plus flexible et peut être utilisé dans n'importe quel environnement. La sauvegarde qu'il produit se compose de fichiers, il est donc parfaitement possible de copier la sauvegarde à n'importe quel endroit que vous aimez. Un autre fournisseur de cloud, votre centre de données local, peu importe tant que vous pouvez transférer des fichiers depuis votre emplacement actuel.

Il n'a même pas besoin d'avoir une connectivité réseau - vous pouvez également copier la sauvegarde sur un périphérique "transférable" comme un SSD USB ou même une clé USB, tant qu'il peut contenir tous les données et stockez-les dans votre poche pendant que vous déménagez d'un centre de données à un autre.

Comment reconstruire un esclave MySQL à l'aide de Xtrabackup ?

Nous avons décidé de nous concentrer sur xtrabackup, compte tenu de sa flexibilité et de sa capacité à fonctionner dans la plupart des environnements où MySQL peut exister. Comment reconstruisez-vous votre esclave à l'aide de xtrabackup ? Jetons un coup d'œil.

Au départ, nous avions un maître et un esclave, qui souffraient de quelques problèmes de réplication :

mysql> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

               Slave_IO_State: Waiting for master to send event

                  Master_Host: 10.0.0.141

                  Master_User: rpl_user

                  Master_Port: 3306

                Connect_Retry: 10

              Master_Log_File: binlog.000004

          Read_Master_Log_Pos: 386

               Relay_Log_File: relay-bin.000008

                Relay_Log_Pos: 363

        Relay_Master_Log_File: binlog.000004

             Slave_IO_Running: Yes

            Slave_SQL_Running: No

              Replicate_Do_DB:

          Replicate_Ignore_DB:

           Replicate_Do_Table:

       Replicate_Ignore_Table:

      Replicate_Wild_Do_Table:

  Replicate_Wild_Ignore_Table:

                   Last_Errno: 1007

                   Last_Error: Error 'Can't create database 'mytest'; database exists' on query. Default database: 'mytest'. Query: 'create database mytest'

                 Skip_Counter: 0

          Exec_Master_Log_Pos: 195

              Relay_Log_Space: 756

              Until_Condition: None

               Until_Log_File:

                Until_Log_Pos: 0

           Master_SSL_Allowed: No

           Master_SSL_CA_File:

           Master_SSL_CA_Path:

              Master_SSL_Cert:

            Master_SSL_Cipher:

               Master_SSL_Key:

        Seconds_Behind_Master: NULL

Master_SSL_Verify_Server_Cert: No

                Last_IO_Errno: 0

                Last_IO_Error:

               Last_SQL_Errno: 1007

               Last_SQL_Error: Error 'Can't create database 'mytest'; database exists' on query. Default database: 'mytest'. Query: 'create database mytest'

  Replicate_Ignore_Server_Ids:

             Master_Server_Id: 1001

                  Master_UUID: 53d96192-53f7-11ea-9c3c-080027c5bc64

             Master_Info_File: mysql.slave_master_info

                    SQL_Delay: 0

          SQL_Remaining_Delay: NULL

      Slave_SQL_Running_State:

           Master_Retry_Count: 86400

                  Master_Bind:

      Last_IO_Error_Timestamp:

     Last_SQL_Error_Timestamp: 200306 11:47:42

               Master_SSL_Crl:

           Master_SSL_Crlpath:

           Retrieved_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:9

            Executed_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:1-8,

ce7d0c38-53f7-11ea-9f16-080027c5bc64:1-3

                Auto_Position: 1

         Replicate_Rewrite_DB:

                 Channel_Name:

           Master_TLS_Version:

       Master_public_key_path:

        Get_master_public_key: 0

            Network_Namespace:

1 row in set (0.00 sec)

Comme vous pouvez le voir, il y a un problème avec l'un des schémas. Supposons que nous devions reconstruire ce nœud pour le ramener dans la réplication. Voici les étapes que nous devons effectuer.

Tout d'abord, nous devons nous assurer que xtrabackup est installé. Dans notre cas, nous utilisons MySQL 8.0, nous devons donc utiliser xtrabackup en version 8 pour assurer la compatibilité :

[email protected]:~# apt install percona-xtrabackup-80

Reading package lists... Done

Building dependency tree

Reading state information... Done

percona-xtrabackup-80 is already the newest version (8.0.9-1.bionic).

0 upgraded, 0 newly installed, 0 to remove and 143 not upgraded.

Xtrabackup est fourni par le référentiel Percona et le guide d'installation peut être trouvé ici :

https://www.percona.com/doc/percona-xtrabackup/8.0/installation/apt_repo.html

L'outil doit être installé à la fois sur le maître et sur l'esclave que nous voulons reconstruire.

Dans une prochaine étape, nous supprimerons toutes les données de l'esclave "cassé" :

[email protected]:~# service mysql stop

[email protected]:~# rm -rf /var/lib/mysql/*

Ensuite, nous prendrons la sauvegarde sur le maître et la diffuserons sur l'esclave. Veuillez garder à l'esprit que ce one-liner particulier nécessite une connectivité racine SSH sans mot de passe du maître à l'esclave :

[email protected] :~# xtrabackup --backup --compress --stream=xbstream --target-dir=./ | ssh [email protected] "xbstream -x --decompress -C /var/lib/mysql/"

À la fin, vous devriez voir une ligne importante :

200306 12:10:40 completed OK!

C'est un indicateur que la sauvegarde s'est terminée correctement. Quelques choses peuvent encore mal tourner, mais au moins nous avons obtenu les bonnes données. Ensuite, sur l'esclave, nous devons préparer la sauvegarde.

[email protected]:~# xtrabackup --prepare --target-dir=/var/lib/mysql/

.

.

.

200306 12:16:07 completed OK!

Vous devriez voir, encore une fois, que le processus s'est terminé correctement. Vous voudrez peut-être maintenant recopier les données dans le répertoire de données MySQL. Nous n'avons pas à le faire car nous avons stocké la sauvegarde en continu directement dans /var/lib/mysql. Ce que nous voulons faire, cependant, c'est garantir la propriété correcte des fichiers :

[email protected]:~# chown -R mysql.mysql /var/lib/mysql

Maintenant, vérifions les coordonnées GTID de la sauvegarde. Nous les utiliserons plus tard lors de la configuration de la réplication.

[email protected]:~# cat /var/lib/mysql/xtrabackup_binlog_info

binlog.000007 195 53d96192-53f7-11ea-9c3c-080027c5bc64:1-9

Ok, tout semble aller bien, démarrons MySQL et procédons à la configuration de la réplication :

[email protected]:~# service mysql start

[email protected]:~# mysql -ppass

mysql: [Warning] Using a password on the command line interface can be insecure.

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 8

Server version: 8.0.18-9 Percona Server (GPL), Release '9', Revision '53e606f'



Copyright (c) 2009-2019 Percona LLC and/or its affiliates

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.



Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.



Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.



mysql>

Nous devons maintenant définir gtid_purged sur l'ensemble GTID que nous avons trouvé dans la sauvegarde. Ce sont des GTID qui ont été "couverts" par notre sauvegarde. Seul le nouveau GTID doit être répliqué à partir du maître.

mysql> SET GLOBAL gtid_purged='53d96192-53f7-11ea-9c3c-080027c5bc64:1-9';

Query OK, 0 rows affected (0.00 sec)

Now we can start the replication:

mysql> CHANGE MASTER TO MASTER_HOST='10.0.0.141', MASTER_USER='rpl_user', MASTER_PASSWORD='yIPpgNE4KE', MASTER_AUTO_POSITION=1;

Query OK, 0 rows affected, 2 warnings (0.02 sec)



mysql> START SLAVE;

Query OK, 0 rows affected (0.00 sec)

mysql> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

               Slave_IO_State: Waiting for master to send event

                  Master_Host: 10.0.0.141

                  Master_User: rpl_user

                  Master_Port: 3306

                Connect_Retry: 60

              Master_Log_File: binlog.000007

          Read_Master_Log_Pos: 380

               Relay_Log_File: relay-bin.000002

                Relay_Log_Pos: 548

        Relay_Master_Log_File: binlog.000007

             Slave_IO_Running: Yes

            Slave_SQL_Running: Yes

              Replicate_Do_DB:

          Replicate_Ignore_DB:

           Replicate_Do_Table:

       Replicate_Ignore_Table:

      Replicate_Wild_Do_Table:

  Replicate_Wild_Ignore_Table:

                   Last_Errno: 0

                   Last_Error:

                 Skip_Counter: 0

          Exec_Master_Log_Pos: 380

              Relay_Log_Space: 750

              Until_Condition: None

               Until_Log_File:

                Until_Log_Pos: 0

           Master_SSL_Allowed: No

           Master_SSL_CA_File:

           Master_SSL_CA_Path:

              Master_SSL_Cert:

            Master_SSL_Cipher:

               Master_SSL_Key:

        Seconds_Behind_Master: 0

Master_SSL_Verify_Server_Cert: No

                Last_IO_Errno: 0

                Last_IO_Error:

               Last_SQL_Errno: 0

               Last_SQL_Error:

  Replicate_Ignore_Server_Ids:

             Master_Server_Id: 1001

                  Master_UUID: 53d96192-53f7-11ea-9c3c-080027c5bc64

             Master_Info_File: mysql.slave_master_info

                    SQL_Delay: 0

          SQL_Remaining_Delay: NULL

      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates

           Master_Retry_Count: 86400

                  Master_Bind:

      Last_IO_Error_Timestamp:

     Last_SQL_Error_Timestamp:

               Master_SSL_Crl:

           Master_SSL_Crlpath:

           Retrieved_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:10

            Executed_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:1-10

                Auto_Position: 1

         Replicate_Rewrite_DB:

                 Channel_Name:

           Master_TLS_Version:

       Master_public_key_path:

        Get_master_public_key: 0

            Network_Namespace:

1 row in set (0.00 sec)

Comme vous pouvez le voir, notre esclave réplique à partir de son maître.

Comment reconstruire un esclave MySQL à l'aide de ClusterControl ?

Si vous êtes un utilisateur de ClusterControl, au lieu de passer par ce processus, vous pouvez reconstruire l'esclave en quelques clics. Au départ, nous avons un problème clair avec la réplication :

Notre esclave ne se réplique pas correctement en raison d'une erreur.

Tout ce que nous avons à faire est d'exécuter la tâche "Rebuild Replication Slave" .

Une boîte de dialogue s'affichera dans laquelle vous devrez choisir un nœud maître pour l'esclave que vous voulez reconstruire. Ensuite, cliquez sur Continuer et vous êtes prêt. ClusterControl reconstruira l'esclave et configurera la réplication pour vous.

Bientôt, en fonction de la taille de l'ensemble de données, vous devriez voir un esclave actif :

Comme vous pouvez le constater, en quelques clics, ClusterControl a accompli la tâche de reconstruction de l'esclave de réplication incohérent.