percona-toolkit验证MySQL主从一致性

参考文章:
http://www.mamicode.com/info-detail-590165.html
http://www.cnblogs.com/zhoujinyi/archive/2013/05/09/3067045.html
http://blog.chinaunix.net/uid-16844903-id-3360228.html

原理解析

pt-table-checksum

pt-table-checksum会智能分析表上的索引,然后把表中的数据splite分成若干chunk,计算的时候以chunk为单位。
对于每一个chunk,把chunk中的每行每列的值都转换为字符串,然后用concat_ws()函数把转换后的字符串都连接起来,计算出该行的checksum值。checksum默认采用crc32计算。
演示如下:(只用作解释原理,与后文无关。)

mysql> insert into test(name) values ('chaoyangqu');
mysql> select * from test; +----+------------+
| id | name | +----+------------+
| 4 | chaoyangqu | +----+------------+
4 rows in set (0.00 sec)

mysql> select concat_ws(',',id,name) from test; +------------------------+
| concat_ws(',',id,name) | +------------------------+
| 4,chaoyangqu | +------------------------+
4 rows in set (0.00 sec)

mysql> select crc32(concat_ws(',',id,name)) from test; +-------------------------------+
| crc32(concat_ws(',',id,name)) | +-------------------------------+
| 1425884295 | +-------------------------------+
4 rows in set (0.00 sec)

crc32函数生成的校验码,会被插入percona库的checksums表中。
因为是主从环境,所以checksums表中的数据也会被复制到slave中。
也就是slave的percona.checksums表中存储的是主库数据的校验码。
所以在slave中对数据执行同样的校验,然后对比checksums表中的数据,就可验证主从是否一致。

所以执行pt-table-checksum命令的帐号,至少需要有全库的只读权限和percona库的读写权限。

如果发生不一致,可以使用pt-table-sync命令修复。

pt-table-sync

主从数据校验的过程,pt-table-sync与pt-table-checksum的算法和原理一样。
再往下,就开始有所不同:
pt-table-checksum只是校验,所以它把checksum结果存储到统计表,然后把执行过的sql语句记录到binlog中,任务就算完成。语句级的复制把计算逻辑传递到从库,并在从库执行相同的计算。pt-table-checksum的算法本身并不在意从库的延迟,延迟多少都一样计算,不会影响计算结果的正确性(但是我们还是会检测延迟,因为延迟太多会影响业务,所以总是要加上—max-lag来限流)。

pt-table-sync则不同。它首先要完成chunk的checksum值的计算,一旦发现主从上同样的chunk的checksum值不同,就深入到该chunk内部,逐行比较并修复有问题的行。其计算逻辑描述如下(以修复主从结构的数据不一致为例,业务双写的情况修复起来更复杂—因为涉及到冲突解决和基准选择的问题。):

对每一个从库,每一个表,循环进行如下校验和修复过程。对每一个chunk,在校验时加上for update锁。一旦获得锁,就记录下当前主库的show master status值。

在从库上执行select master_pos_wait()函数,等待从库sql线程执行到show master status得到的位置。以此保证,主从上关于这个chunk的内容均不再改变。

对这个chunk执行checksum,然后与主库的checksum进行比较。

如果checksum相同,说明主从数据一致,就继续下一个chunk。

如果checksum不同,说明该chunk有不一致。深入chunk内部,逐行计算checksum并比较(单行的checksum的比较过程与chunk的比较过程一样,单行实际是chunk的size为1的特例)。

如果发现某行不一致,则标记下来。继续检测剩余行,直到这个chunk结束。

对找到的主从不一致的行,采用replace into语句,在主库执行一遍以生成该行全量的binlog,并同步到从库,这会以主库数据为基准来修复从库;对于主库有的行而从库没有的行,采用replace在主库上插入(必须不能是insert);对于从库有而主库没有的行,通过在主库执行delete来删除(pt-table-sync强烈建议所有的数据修复都只在主库进行,而不建议直接修改从库数据;但是也有特例。)。

直到修复该chunk所有不一致的行。继续检查和修复下一个chunk。

直到这个从库上所有的表修复结束。开始修复下一个从库。

应用场景

pt-table-checksum是一个在线验证主从数据一致性的工具,主要用于以下场景:
1. 数据迁移前后,进行数据一致性检查
2. 当主从复制出现问题,待修复完成后,对主从数据进行一致性检查
3. 把从库当成主库,进行数据更新,产生了”脏数据”
4. 定期校验

获取最近版本percona-toolkit并安装

[root@mysqlrep1 tmp]# export LANG=C
[root@mysqlrep1 tmp]# wget https://www.percona.com/downloads/percona-toolkit/2.2.16/RPM/percona-toolkit-2.2.16-1.noarch.rpm

[root@mysqlrep1 tmp]# ll
total 307388
-rw-r--r--  1 root   root   313028660 Feb 16 20:08 mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz
-rw-r--r--  1 root   root     1714826 Nov  9 19:20 percona-toolkit-2.2.16-1.noarch.rpm
-rw-------. 1 root   root           0 Feb 16 07:51 yum.log
-rw-rw-r--  1 zabbix zabbix     13045 Feb 16 22:10 zabbix_agentd.log
[root@mysqlrep1 tmp]# 

[root@mysqlrep1 tmp]# yum localinstall percona-toolkit-2.2.16-1.noarch.rpm 

主库建立测试数据,从库上验证复制正常

主库:

mysql> create database ljk;
mysql> use ljk;
Database changed
mysql> create table test(id serial,name varchar(20));
Query OK, 0 rows affected (0.06 sec)

mysql> insert into test(name) values ('hello'),('beijing'),('shandong');
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from test; +----+----------+
| id | name | +----+----------+
|  1 | hello    |
|  2 | beijing  |
| 3 | shandong | +----+----------+
3 rows in set (0.00 sec)

从库:

mysql> use ljk;
Database changed
mysql> select * from test; +----+----------+
| id | name | +----+----------+
|  1 | hello    |
|  2 | beijing  |
| 3 | shandong | +----+----------+
3 rows in set (0.00 sec)

从库上修改数据,模拟不一致场景

mysql> insert into test(name) values ('chaoyangqu');
Query OK, 1 row affected (0.00 sec)

主库上执行主从校验命令

建立主从校验所需账户

mysql> GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'lijingkuan'@'%' IDENTIFIED BY 'lijingkuan';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on percona.* TO 'lijingkuan'@'%' IDENTIFIED BY 'lijingkuan';
Query OK, 0 rows affected (0.00 sec)

执行主从校验

[root@mysqlrep1 tmp]# pt-table-checksum --user=lijingkuan --password=lijingkuan --recursion-method=processlist --databases=ljk --no-check-binlog-format TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 02-24T01:05:57      0      1        3       1       0   0.289 ljk.test
[root@mysqlrep1 tmp]# 

主从校验结果
(自动创建了percona库和checksums表)

mysql> show databases; +--------------------+
| Database | +--------------------+
| information_schema | | ljk | | mysql | | percona | | performance_schema |
| test | +--------------------+
6 rows in set (0.00 sec)

mysql> use percona;
mysql> show tables; +-------------------+
| Tables_in_percona | +-------------------+
| checksums | +-------------------+
1 row in set (0.00 sec)

mysql> select * from checksums; +-----+------+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
| db | tbl | chunk | chunk_time | chunk_index | lower_boundary | upper_boundary | this_crc | this_cnt | master_crc | master_cnt | ts | +-----+------+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
| ljk | test | 1 | 0.027644 | NULL | NULL | NULL | 7a1300c8 | 3 | 7a1300c8 | 3 | 2016-02-24 01:05:57 | +-----+------+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
1 row in set (0.00 sec)

mysql> exit
Bye

修复主从不一致数据

查看需要执行的SQL语句
使用print参数,他会在屏幕显示修复的SQL语句。然后可以手工确认并执行。

[root@mysqlrep1 tmp]# pt-table-sync --print --replicate=percona.checksums h=192.168.56.211,u=root,p=123456,P=3306 h=192.168.56.212,u=root,p=123456,P=3306
DELETE FROM `ljk`.`test` WHERE `id`='4' LIMIT 1 /*percona-toolkit src_db:ljk src_tbl:test src_dsn:P=3306,h=192.168.56.211,p=...,u=root dst_db:ljk dst_tbl:test dst_dsn:P=3306,h=192.168.56.212,p=...,u=root lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:4795 user:root host:mysqlrep1.cwlc.com.cn*/;
[root@mysqlrep1 tmp]# 
[root@mysqlrep1 tmp]# 

直接执行修复

[root@mysqlrep1 tmp]# pt-table-sync --execute --sync-to-master h=192.168.56.212,u=root,p=123456,P=3306 --databases ljk --tables test
[root@mysqlrep1 tmp]# 

用户权限及命令参数解析

–replicate= :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。
举例:–replicate=test.checksums 将校验数据写入test数据库的checksums表中。
–databases= :指定需要被检查的数据库,多个则用逗号隔开。
–tables= :指定需要被检查的表,多个用逗号隔开
–chunk-size, –chunk-size-limit 用于指定检测块的大小。 可控性更强。
–lock-wait-timeout innodb 锁的超时设定, 默认为1。
–max-load 设置最大并发连接数。
–ask-pass 要是在shell窗口不想显示的输入密码则可以添加–ask-pass 参数。

遇到的问题

Diffs cannot be detected because no slaves were found.  Please read the --recursion-method documentation for information.

原因:
pt-table-checksum默认查找备库的方式是使用SHOW PROCESSLIST。
如果非标准的3306端口,就使用SHOW SLAVE HOSTS的方式,推荐使用dsn方式,手动指定。
所以执行pt-table-checksum的数据库账户要有process和replication slave权限。
解决方案:
加上参数 –recursion-method=processlist

Replica mysqlrep2.cwlc.com.cn has binlog_format ROW which could cause pt-table-checksum to break replication.  Please read "Replicas using row-based replication" in the LIMITATIONS section of the tool's documentation.  If you understand the risks, specify --no-check-binlog-format to disable this check.

原因及解决办法:
pt-table-checksum requires statement-based replication, and it sets binlog_format=STATEMENT on the master, but due to a MySQL limitation replicas do not honor this change. Therefore, checksums will not replicate past any replicas using row-based replication that are masters for further replicas.

The tool automatically checks the binlog_format on all servers. See –[no]check-binlog-format .

(Bug 899415)

其他说明

1.要是表中没有唯一索引或则主键则会报错:
Can’t make changes on the master because no unique index exists at /usr/local/bin/pt-table-sync line 10591.

2.要是从库有的数据,而主库没有,那这个数据怎么处理?会给出删除SLAVE多余数据,和修复SLAVE缺失数据的SQL语句。

你可能感兴趣的:(percona-toolkit验证MySQL主从一致性)