Актуализация реплики mysql с помощью pt-table-checksum и pt-table-sync
При использовании механизма репликации mysql необходимо иметь идентичные наборы данных на всех серверах участвующих в схеме.
Если появляется расхождение данных необходимо его устранить. Это можно сделать пересозданием slave реплики (что не всегда удобно) или воспользоваться утилитами pt-table-checksum и pt-table-sync. Далее я опишу работу с этими утилитами на примере Linux Debian.
Схема серверов простая — один master (node-master) и два slave (node-slave-1, node-slave-2) сервера. На всех серверах нужно установить пакет percona-toolkit в который входят утилиты pt-table-checksum и pt-table-sync.
apt-get update apt-get install percona-toolkit |
Создаем тестовую базу
mysql> create database test; Query OK, 0 rows affected (0.02 sec) mysql> create table table1 (id int(11) not null auto_increment primary key, name char(5)) engine=innodb; Query OK, 0 rows affected (0.02 sec) mysql> insert into table1 VALUES (1,'a'), (2,'b'), (3,'c'), (4,'d'), (5,'e'), (6,'f'), (7,'g'), (8,'h'), (9,'i'), (10,'j'); Query OK, 10 rows affected (0.00 sec) Records: 10 Duplicates: 0 Warnings: 0 mysql> select * from table1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | | 6 | f | | 7 | g | | 8 | h | | 9 | i | | 10 | j | +------+------+ 10 rows in set (0.00 sec) |
Теперь удалим часть данных на slave серверах
node-slave-1
mysql> delete from table1 where id>7; Query OK, 3 rows affected (0.00 sec) mysql> select * from table1; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | | 6 | f | | 7 | g | +----+------+ 7 rows in set (0.00 sec) |
node-slave-2
mysql> delete from table1 where id<5; Query OK, 4 rows affected (0.00 sec) mysql> select * from table1; +----+------+ | id | name | +----+------+ | 5 | e | | 6 | f | | 7 | g | | 8 | h | | 9 | i | | 10 | j | +----+------+ 6 rows in set (0.00 sec) |
Для работы percona-toolkit необходимо на всех серверах создать таблицу и пользователя
mysql> CREATE DATABASE PERCONA; Query OK, 1 row affected (0.00 sec) mysql> USE PERCONA; Database changed mysql> CREATE TABLE checksums ( -> db CHAR(64) NOT NULL, -> tbl CHAR(64) NOT NULL, -> chunk INT NOT NULL, -> chunk_time FLOAT NULL, -> chunk_index VARCHAR(200) NULL, -> lower_boundary TEXT NULL, -> upper_boundary TEXT NULL, -> this_crc CHAR(40) NOT NULL, -> this_cnt INT NOT NULL, -> master_crc CHAR(40) NULL, -> master_cnt INT NULL, -> ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -> PRIMARY KEY (db, tbl, chunk), -> INDEX ts_db_tbl (ts, db, tbl) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.01 sec) mysql> GRANT REPLICATION SLAVE,PROCESS,SUPER, SELECT ON *.* TO `checksum_user`@'%' IDENTIFIED BY 'checksum_password'; Query OK, 0 rows affected (0.00 sec) mysql> GRANT ALL PRIVILEGES ON percona.* TO `checksum_user`@'%'; Query OK, 0 rows affected (0.03 sec) mysql> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) |
После создания таблицы и пользователя, запускаем проверку целостности данных
root@node-server:/# pt-table-checksum --replicate=percona.checksums --databases=test --host=localhost --user=checksum_user --password=checksum_password TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 09-01T14:07:26 0 1 10 1 0 0.013 test.table1 |
По результатам видим что поле DIFFS отличное от 0. Можно подключиться к slave серверам и проверить в каких таблицах поврежденные данные.
node-slave-1
mysql> SELECT db, tbl, SUM(this_cnt) AS total_rows, COUNT(*) AS chunks -> FROM percona.checksums -> WHERE ( -> master_cnt <> this_cnt -> OR master_crc <> this_crc -> OR ISNULL(master_crc) <> ISNULL(this_crc)) -> GROUP BY db, tbl; +------+--------+------------+--------+ | db | tbl | total_rows | chunks | +------+--------+------------+--------+ | test | table1 | 7 | 1 | +------+--------+------------+--------+ 1 row in set (0.00 sec) |
node-slave-2
mysql> SELECT db, tbl, SUM(this_cnt) AS total_rows, COUNT(*) AS chunks -> FROM percona.checksums -> WHERE ( -> master_cnt <> this_cnt -> OR master_crc <> this_crc -> OR ISNULL(master_crc) <> ISNULL(this_crc)) -> GROUP BY db, tbl; +------+--------+------------+--------+ | db | tbl | total_rows | chunks | +------+--------+------------+--------+ | test | table1 | 6 | 1 | +------+--------+------------+--------+ 1 row in set (0.00 sec) |
На каждом slave сервере выполняем команду синхронизации данных.
node-slave-1
root@node-slave-1:/# pt-table-sync --print --replicate=percona.checksums --sync-to-master h=localhost,u=checksum_user,p=checksum_password # A software update is available: # * The current version for Percona::Toolkit is 3.0.5 REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('8', 'h') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:3248 user:root host:node-slave-1*/; REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('9', 'i') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:3248 user:root host:node-slave-1*/; REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('10', 'j') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:3248 user:root host:node-slave-1*/; |
node-slave-2
root@node-slave-2:/# pt-table-sync --print --replicate=percona.checksums --sync-to-master h=localhost,u=checksum_user,p=checksum_password # A software update is available: # * The current version for Percona::Toolkit is 3.0.5 REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('1', 'a') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:2566 user:root host:node-slave-2*/; REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('2', 'b') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:2566 user:root host:node-slave-2*/; REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('3', 'c') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:2566 user:root host:node-slave-2*/; REPLACE INTO `test`.`table1`(`id`, `name`) VALUES ('4', 'd') /*percona-toolkit src_db:test src_tbl:table1 src_dsn:P=3306,h=192.168.5.56,p=...,u=checksum_user dst_db:test dst_tbl:table1 dst_dsn:h=localhost,p=...,u=checksum_user lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:2566 user:root host:node-slave-2*/; |
Ключ —print выводит запросы для актуализации данных, без выполнения. Можно в ручную выполнить их или запустить команду заменив ключ —print на —execute
После выполнения команды нужно проверить что данные синхронизированы. Повторно запускаем проверку на master
root@node-server:/# pt-table-checksum --replicate=percona.checksums --databases=test --host=localhost --user=checksum_user --password=checksum_password TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 09-01T14:15:17 0 0 10 1 0 1.015 test.table1 |