sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo reconstruir un esclavo MySQL inconsistente?

Los esclavos MySQL pueden volverse inconsistentes. Puedes intentar evitarlo, pero es muy difícil. Establecer super_read_only y usar la replicación basada en filas puede ayudar mucho, pero no importa lo que haga, aún es posible que su esclavo se vuelva inconsistente.

¿Qué se puede hacer para reconstruir un esclavo MySQL inconsistente? En esta publicación de blog, analizaremos este problema.

Primero, analicemos lo que tiene que suceder para reconstruir un esclavo. Para llevar un nodo a la replicación de MySQL, se debe aprovisionar con datos de uno de los nodos en la topología de replicación. Estos datos deben ser coherentes en el momento en que se recopilaron. No puede tomarlo tabla por tabla o esquema por esquema, porque esto hará que el nodo aprovisionado sea inconsistente internamente. Lo que significa que algunos datos serían más antiguos que alguna otra parte del conjunto de datos.

Además de la coherencia de los datos, también debería ser posible recopilar información sobre la relación entre los datos y el estado de replicación. Desea tener una posición de registro binario en la que los datos recopilados sean coherentes o el ID de transacción global de la transacción que fue la última que se ejecutó en el nodo que es el origen de los datos.

Esto nos lleva a las siguientes consideraciones. Puede reconstruir un esclavo con cualquier herramienta de copia de seguridad siempre que esta herramienta pueda generar una copia de seguridad coherente e incluya las coordenadas de replicación para el punto en el tiempo en el que la copia de seguridad es coherente. Esto nos permite elegir entre un par de opciones.

Uso de Mysqldump para reconstruir un esclavo MySQL inconsistente

Mysqldump es la herramienta más básica que tenemos para lograr esto. Nos permite crear una copia de seguridad lógica, entre otros, en forma de sentencias SQL. Lo que es importante, si bien es básico, aún nos permite realizar una copia de seguridad consistente:puede usar la transacción para garantizar que los datos sean consistentes al comienzo de la transacción. También puede escribir las coordenadas de replicación para ese punto, incluso una instrucción CHANGE MASTER completa, lo que facilita el inicio de la replicación utilizando la copia de seguridad.

Uso de Mydumper para reconstruir un esclavo MySQL inconsistente

Otra opción es usar mydumper:esta herramienta, al igual que mysqldump, genera una copia de seguridad lógica y, al igual que mysqldump, se puede usar para crear una copia de seguridad coherente de la base de datos. La principal diferencia entre mydumper y mysqldump es que mydumper, cuando se combina con myloader, puede volcar y restaurar datos en paralelo, mejorando el tiempo de volcado y, especialmente, de restauración.

Uso de una instantánea para reconstruir un esclavo MySQL inconsistente

Para aquellos que usan proveedores de la nube, una posibilidad es tomar una instantánea del almacenamiento de bloques subyacente. Las instantáneas generan una vista puntual de los datos. Sin embargo, este proceso es bastante complicado, ya que la consistencia de los datos y la capacidad de restaurarlos depende principalmente de la configuración de MySQL.

Debe asegurarse de que la base de datos funcione en un modo duradero (está configurada de manera que el bloqueo de MySQL no resulte en ninguna pérdida de datos). Esto se debe a que (desde el punto de vista de MySQL) tomar una instantánea de volumen y luego iniciar otra instancia de MySQL a partir de los datos almacenados en ella es, básicamente, el mismo proceso como si matara -9 el mysqld y luego lo iniciara de nuevo. La recuperación de InnoDB tiene que ocurrir, reproducir las transacciones que se han almacenado en registros binarios, revertir las transacciones que no se completaron antes del bloqueo, etc.

La desventaja del proceso de reconstrucción basado en instantáneas es que está fuertemente vinculado al proveedor actual. No puede copiar fácilmente los datos de la instantánea de un proveedor de nube a otro. Es posible que pueda moverlo entre diferentes regiones, pero seguirá siendo el mismo proveedor.

Uso de Xtrabackup o Mariabackup para reconstruir un esclavo MySQL inconsistente

Finalmente, xtrabackup/mariabackup - esta es una herramienta escrita por Percona y bifurcada por MariaDB que permite generar una copia de seguridad física. Es mucho más rápido que las copias de seguridad lógicas, está limitado principalmente por el rendimiento del hardware, siendo el disco o la red los cuellos de botella más probables. La mayor parte de la carga de trabajo está relacionada con la copia de archivos del directorio de datos de MySQL a otra ubicación (en el mismo host o en la red).

Si bien no es tan rápido como las instantáneas de almacenamiento en bloque, xtrabackup es mucho más flexible y se puede usar en cualquier entorno. La copia de seguridad que produce consta de archivos, por lo que es perfectamente posible copiar la copia de seguridad en cualquier ubicación que desee. Otro proveedor de nube, su centro de datos local, no importa siempre que pueda transferir archivos desde su ubicación actual.

Ni siquiera tiene que tener conectividad de red; también puede copiar la copia de seguridad a algún dispositivo "transferible" como SSD USB o incluso una memoria USB, siempre que pueda contener todos los datos y guárdelos en su bolsillo mientras se traslada de un centro de datos a otro.

¿Cómo reconstruir un esclavo MySQL usando Xtrabackup?

Decidimos centrarnos en xtrabackup, dada su flexibilidad y capacidad para funcionar en la mayoría de los entornos donde puede existir MySQL. ¿Cómo reconstruyes tu esclavo usando xtrabackup? Echemos un vistazo.

Inicialmente, tenemos un maestro y un esclavo, que sufrieron algunos problemas de replicación:

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)

Como puede ver, hay un problema con uno de los esquemas. Supongamos que tenemos que reconstruir este nodo para devolverlo a la replicación. Estos son los pasos que tenemos que realizar.

Primero, debemos asegurarnos de que xtrabackup esté instalado. En nuestro caso, usamos MySQL 8.0, por lo tanto, debemos usar xtrabackup en la versión 8 para garantizar la compatibilidad:

[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 es proporcionado por el repositorio de Percona y la guía para instalarlo se puede encontrar aquí:

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

La herramienta debe instalarse tanto en el maestro como en el esclavo que queremos reconstruir.

Como siguiente paso, eliminaremos todos los datos del esclavo "roto":

[email protected]:~# service mysql stop

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

A continuación, tomaremos la copia de seguridad en el maestro y la transmitiremos al esclavo. Tenga en cuenta que esta frase en particular requiere conectividad raíz SSH sin contraseña desde el maestro al esclavo:

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

Al final debería ver una línea importante:

200306 12:10:40 completed OK!

Este es un indicador de que la copia de seguridad se completó correctamente. Un par de cosas aún pueden salir mal, pero al menos obtuvimos los datos correctos. A continuación, en el esclavo, tenemos que preparar la copia de seguridad.

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

.

.

.

200306 12:16:07 completed OK!

Debería ver, nuevamente, que el proceso se completó correctamente. Es posible que desee volver a copiar los datos en el directorio de datos de MySQL. No tenemos que hacer eso ya que almacenamos la copia de seguridad de la transmisión directamente en /var/lib/mysql. Sin embargo, lo que queremos hacer es garantizar la propiedad correcta de los archivos:

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

Ahora, verifiquemos las coordenadas GTID de la copia de seguridad. Los usaremos más adelante cuando configuremos la replicación.

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

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

Ok, todo parece estar bien, iniciemos MySQL y procedamos a configurar la replicación:

[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>

Ahora tenemos que configurar el gtid_purged al conjunto de GTID que encontramos en la copia de seguridad. Esos son GTID que han sido "cubiertos" por nuestra copia de seguridad. Solo el nuevo GTID debe replicarse desde el maestro.

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)

Como puede ver, nuestro esclavo se está replicando desde su maestro.

¿Cómo reconstruir un esclavo MySQL usando ClusterControl?

Si es usuario de ClusterControl, en lugar de pasar por este proceso, puede reconstruir el esclavo con solo un par de clics. Inicialmente, tenemos un problema claro con la replicación:

Nuestro esclavo no se replica correctamente debido a un error.

Todo lo que tenemos que hacer es ejecutar el trabajo "Reconstruir esclavo de replicación" .

Se le presentará un cuadro de diálogo donde debe elegir un nodo maestro para el esclavo que quieres reconstruir. Luego, haga clic en Continuar y ya está todo listo. ClusterControl reconstruirá el esclavo y configurará la replicación por usted.

En breve, según el tamaño del conjunto de datos, debería ver esclavo en funcionamiento:

Como puede ver, con solo un par de clics, ClusterControl logró la tarea de reconstruir el esclavo de replicación inconsistente.