Mantener la consistencia de los datos en la replicación

Las replicaciones necesitan de un chequeo constante en la integridad de los datos. Fallos de disco, corrupción de de logs, mezcla de tablas transaccionales y no transaccionales y otros problemas pueden tumbar la consistencia de nuestros datos. Por lo tanto, podemos tener una replicación funcionando, pero los datos, si no hay una comprobación activa, pueden ser diferentes en las dos máquinas. MySQL no tiene comprobaciones activas de consistencia, por lo que es trabajo nuestro. Para ello, instalamos las herramientas maatkit de Percona:

apt-get install maatkit

Las herramientras que usaremos serán mk-table-checksum y mk-table-sync. El funcionamiento de la herramienta se basa en la replicación en base a sentencias de mysql. mk-table-checksum realiza una comprobación mediante un algoritmo de hashing en las tablas, escribiendo los resultados en la base de datos. Estas sentencias se replicarán en el esclavo y se volverán a ejecutar, realizando por lo tanto el mismo hashing en las tablas del esclavo. De esta forma, unicamente debemos comparar los resultados en el maestro y en el esclavo para comprobar si los datos son exactamente iguales o no.

Tenemos dos MySQL en Master-Slave.

NODO 1:

Puerto TCP 19369

master [localhost] {msandbox} (vida) > select * from producto;
+---+--------+
| i | nombre |
+---+--------+
| 1 | VPS    |
| 2 | Cloud  |
+---+--------+
2 rows in set (0.00 sec)

NODO 2:

Puerto TCP 19370

slave1 [localhost] {msandbox} (vida) > select * from producto;
+---+---------+
| i | nombre  |
+---+---------+
| 1 | VPS     |
| 2 | Cloud   |
| 3 | Storage |
+---+---------+
3 rows in set (0.00 sec)

¿Como comprobamos si los datos son o no consistentes?

Primero, le decimos a mk-table-checksum que haga un checksum de todas las tablas de la base de datos vida y guarde el resultado en test.checksum.

~$ mk-table-checksum u=root,p=msandbox
--socket=/tmp/mysql_sandbox19369.sock --databases=vida
--replicate test.checksum --create-replicate-table
Cannot connect to P=19369,S=/tmp/mysql_sandbox19369.sock,h=SBslave1,p=...,u=root
Cannot connect to P=19369,S=/tmp/mysql_sandbox19369.sock,h=SBslave1,p=...,u=root
DATABASE TABLE    CHUNK HOST        ENGINE      COUNT         CHECKSUM TIME WAIT STAT  LAG
vida     producto     0 soporteit69 InnoDB          2         935b4964    0 NULL NULL NULL

Comprobamos los resultados en Master:

master [localhost] {msandbox} (test) > select * from checksum;
+------+----------+-------+------------+----------+----------+------------+------------+
| db   | tbl      | chunk | boundaries | this_crc | this_cnt | master_crc | master_cnt |
+------+----------+-------+------------+----------+----------+------------+------------+
| vida | producto |     0 | 1=1        | 935b4964 |        2 | 935b4964   |          2 |
+------+----------+-------+------------+----------+----------+------------+------------+
1 row in set (0.00 sec)

Comprobamos los resultados en Slave:

slave1 [localhost] {msandbox} (test) > select * from checksum;
+------+----------+-------+------------+----------+----------+------------+------------+
| db   | tbl      | chunk | boundaries | this_crc | this_cnt | master_crc | master_cnt |
+------+----------+-------+------------+----------+----------+------------+------------+
| vida | producto |     0 | 1=1        | 6120c018 |        3 | 935b4964   |          2 |
+------+----------+-------+------------+----------+----------+------------+------------+
1 row in set (0.00 sec)

Como podemos ver, el crc del slave (this_crc) es diferente al del master (master_crc) por lo tanto, tenemos incosistencias en los datos de la tabla producto de la base de datos vida.

¿Cómo lo arreglamos?

Podriamos hacerlo volviendo a montar la replicación de cero usando un dump de mysqldump. Esto vale si tu BBDD ocupa solo unos cientos de megas, pero si hablamos de gigas, puedes tardar horas y provocar caidas del sistema. Así que haremos uso de mk-table-sync.

~$ mk-table-sync --execute --replicate test.checksum 
--sync-to-master u=root,p=msandbox --socket=/tmp/mysql_sandbox19370.sock

Comprobamos si ahora los datos son consistentes:

master [localhost] {msandbox} (vida) > select * from producto;
+---+--------+
| i | nombre |
+---+--------+
| 1 | VPS    |
| 2 | Cloud  |
+---+--------+
2 rows in set (0.00 sec)
slave1 [localhost] {msandbox} (vida) > select * from producto;
+---+--------+
| i | nombre |
+---+--------+
| 1 | VPS    |
| 2 | Cloud  |
+---+--------+
2 rows in set (0.00 sec)
slave1 [localhost] {msandbox} (test) > select * from checksum;
+------+----------+-------+------------+----------+----------+------------+------------+
| db   | tbl      | chunk | boundaries | this_crc | this_cnt | master_crc | master_cnt |
+------+----------+-------+------------+----------+----------+------------+------------+
| vida | producto |     0 | 1=1        | 935b4964 |        2 | 935b4964   |          2 |
+------+----------+-------+------------+----------+----------+------------+------------+
1 row in set (0.00 sec)

Listo! Replicación consistente y en marcha 😀