相信很多人的线上都搭建了MySQL主从这样的框架,很多人只监控MySQL的从服务器Slave_IO和Slave_SQL这两个线程是否为YES,还有 Seconds_Behind_Master延迟大不大之类的一些信息。但他们是否定期的去检查MySQL主服务器的数据和从服务器的数据是否一致呢,数据一致性才是最重要的,有人很好奇的问,如果数据不一致,就肯定没有两个YES的出现啦,我想说,不一定的,因为当slave出现错误时,可以通过SET GLOBAL sql_slave_skip_counter = N来跳过错误,还有可以通过选项--slave-skip-errors=[error_code]来跳过错误代码,这样处理后Slave_IO和Slave_SQL状态依然为YES,但这个时候,数据可能就跟主库不一致了。下面和大家学习一个很不错的工具pt-table-checksum
pt-table-checksum:MySQL复制完整性校验(这个工具的重点是找到有效数据的差异。如果任何数据是不同的,你可以用pt-table-sync解决问题。)
软件包下载地址:http://www.percona.com/downloads/percona-toolkit/2.2.7/RPM/percona-toolkit-2.2.7-1.noarch.rpm
PT工具的安装,可以参考我的博客:http://www.cnblogs.com/xuanzhi201111/p/4128894.html(主库和从库都要安装)
实验环境: master(192.168.1.128:3306)
slave(192.168.1.129:3306)
注意事项:
1、 根据测试,需要一个即能登录主库,也能登录从库的账号;
2、 只能指定一个host,必须为主库的IP;
3、 在检查时会向表加S锁;
4、 如果master和slave的binlog日志不是STATEMENT格式,要用--no-check-binlog-format选项
5、 运行之前需要从库的同步IO和SQL进程是YES状态。
6、 表要有主键索引或唯一键索引
在主库上(master:3306),如下:
mysql> select * from check_sum.test1; +------+-------+ | id | couse | +------+-------+ | 1 | aa | | 2 | bb | | 3 | cc | +------+-------+ 3 rows in set (0.00 sec) mysql>
在从库(slave:3306),如下(跟master数据不一致了):
mysql> select * from check_sum.test1; +------+-------+ | id | couse | +------+-------+ | 1 | aa | | 2 | bb | +------+-------+ 2 rows in set (0.00 sec) mysql>
pt-table-checksum参数解释:
--nocheck-replication-filters :不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。 --no-check-binlog-format : 不检查复制的binlog模式,要是binlog模式是ROW,则会报错。 --replicate-check-only :只显示不同步的信息。 --replicate= :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。 --databases= :指定需要被检查的数据库,多个则用逗号隔开。 --tables= :指定需要被检查的表,多个用逗号隔开 h=192.168.1.128 :Master的地址 u=root :用户名 p=123456 :密码 P=3306 :端口
在主库上执行数据检查命令:
[root ~]$ pt-table-checksum --nocheck-replication-filters --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 Replica slave has binlog_format MIXED 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.
上面报错了,意思说如果binlog_format 为MIXED格式,会破坏同步,可以使用--no-check-binlog-format选项来关闭检查
添加上--no-check-binlog-format选项,再在master库上执行,报以下错(标红的为报错信息):
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 Cannot connect to P=3306,h=192.168.1.129,p=...,u=root Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information. TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 04-13T15:44:23 0 0 3 1 0 0.044 check_sum.test1
上面已经告诉你怎么做了, Please read the --recursion-method documentation for information,上面的提示信息很清楚,因为找不到slave库,所以执行失败。用参数--recursion-method 可以指定模式解决,关于--recursion-method参数的设置有:
METHOD USES =========== ============================================= processlist SHOW PROCESSLIST hosts SHOW SLAVE HOSTS cluster SHOW STATUS LIKE 'wsrep\_incoming\_addresses' dsn=DSN DSNs from a table none Do not find slaves
默认是通过show processlist 找到host的值或show slave hosts 找到host的值
*************************** 1. row *************************** Id: 7 User: admin Host: 192.168.1.129:60195 db: NULL Command: Binlog Dump Time: 663201 State: Master has sent all binlog to slave; waiting for binlog to be updated Info: NULL *************************** 2. row *************************** Id: 37 User: root Host: localhost db: check_sum Command: Query Time: 0 State: NULL Info: show processlist 4 rows in set (0.00 sec)
还有一种方法是show slave hosts;前提从库配置文件里面已经配置自己的地址和端口,在slave库上操作(在[mysqld]下添加这两行):
[root mysql-5.5.40]$ cat my.cnf |grep "report" report_host=192.168.1.129 report_port=3306
回到master库操作:
mysql> show slave hosts; +-----------+---------------+------+-----------+ | Server_id | Host | Port | Master_id | +-----------+---------------+------+-----------+ | 11 | 192.168.1.129 | 3306 | 1 | +-----------+---------------+------+-----------+ 1 row in set (0.00 sec) mysql>
最重要的一点是我们需要在从库上授权,能让主库访问,只能指定一个host,必须为主库的IP,在slave库上操作;
mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'admin'@'192.168.1.128' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql>
如果在master没有让admin用户登录的权利,要在master库给admin权限,很多人用root用户来检查,所以只要在从库权限即可(在master库上操作):
mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'admin'@'192.168.1.128' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql>
权限解释:
select //查看所有库的表,原理可加 explain选项查看 process //show processlist super //set binlog_format='statement' replication slave //show slave hosts
现在我们再来检测数据一致性(master库上操作):
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T15:38:30 0 1 3 1 0 0.339 check_sum.test1
看到已经检查出主从数据有不一致了,DIFFS下的值为1,怎么不一致呢? 通过指定--replicate=test.checksums 参数,就说明把检查信息都写到了checksums表中
下面对例的含义进行解释:
TS :完成检查的时间。 ERRORS :检查时候发生错误和警告的数量。 DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。 ROWS :表的行数。 CHUNKS :被划分到表中的块的数目。 SKIPPED :由于错误或警告或过大,则跳过块的数目。 TIME :执行的时间。 TABLE :被检查的表名。
之前一直以为去master的test.checksums表查看主库与从库不一致的信息,纠结了N久,前面显示了DIFFS下的值为1,但master上看表里的信息如下:
mysql> select * from test.checksumsG *************************** 1. row *************************** db: check_sum tbl: test1 chunk: 1 chunk_time: 0.023619 chunk_index: NULL lower_boundary: NULL upper_boundary: NULL this_crc: d5b7731c #slave this_cnt: 3 #slave master_crc: d5b7731c #master master_cnt: 3 #master ts: 2014-12-26 15:50:29 1 row in set (0.00 sec) mysql>
看到了吧,它们信息一样,正常来说,表里信息应该是master跟slave不一致才对的,现在是一致,如果test.checksum里的对比是一样的,是不能把slave库少了的数据从master库同步过去的,因为pt-table-sync同步数据时,要借助test.checksum表。别急:我们再去看一下slave库下的test.checksums:(slave库操作)
mysql> select * from test.checksumsG *************************** 1. row *************************** db: check_sum tbl: test1 chunk: 1 chunk_time: 0.023619 chunk_index: NULL lower_boundary: NULL upper_boundary: NULL this_crc: 64fdcfa3 this_cnt: 2 #slave 2行数据 master_crc: d5b7731c master_cnt: 3 #master 3行数据 ts: 2014-12-26 15:50:29 1 row in set (0.00 sec)
在master库可以可以用--print选项打印出master下的check_sum.test1和slave库的check_sum.test1的不一致的数据,如下:
[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --print Can't make changes on the master because no unique index exists at /usr/bin/pt-table-sync line 10648. while doing check_sum.test1 on 192.168.1.129
以上报错了,报错信息也很明显,说表没有唯一索引,在master库上给表添加主键索引或者唯一索引:
mysql> alter table test1 add primary key (id); Query OK, 3 rows affected (0.17 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> show create table test1G *************************** 1. row *************************** Table: test1 Create Table: CREATE TABLE `test1` ( `id` int(11) NOT NULL DEFAULT '0', `couse` char(10) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) mysql>
再在master执行一次pt-table-checksum,再执行pt-table-sync,如下:
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T17:16:50 0 1 3 1 0 0.151 check_sum.test1
[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --print REPLACE INTO `check_sum`.`test1`(`id`, `couse`) VALUES ('3', 'cc') /*percona-toolkit src_db:check_sum src_tbl:test1 src_dsn:P=3306,h=192.168.1.128,p=...,u=admin dst_db:check_sum dst_tbl:test1 dst_dsn:P=3306, h=192.168.1.129,p=...,u=admin lock:1 transaction:1 changing_src:test.checksums replicate:test.checksums bidirectional:0 pid:41368 user:root host:localhost.localdomain*/;
大家都看到了有不一致的数据记录了吧
参数说明:
--replicate= :指定通过pt-table-checksum得到的表. --databases= : 指定执行同步的数据库,多个用逗号隔开。 --tables= :指定执行同步的表,多个用逗号隔开。 --sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。 h=127.0.0.1 :服务器地址,命令里有2个ip,第一次出现的是Master的地址,第2次是Slave的地址。 u=root :帐号。 p=123456 :密码。 --print :打印,但不执行命令。 --execute :执行命令。
接下的操作就是把slave上少的数据,从master同步过去(master操作):
通过(--execute),让它们数据保持一致性:
[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --execute INSERT,DELETE command denied to user 'admin'@'192.168.1.128' for table 'test1' [for Statement "REPLACE INTO `check_sum`.`test1`(`id`, `couse`) VALUES ('3', 'cc') /*percona-toolkit src_db:check_sum src_tbl:test1 src_dsn:P=3306,h=192.168.1.128,p=...,u=admin dst_db:check_sum dst_tbl:test1 dst_dsn:P=3306,h=192.168.1.129,p=...,u=admin lock:1 transaction:1 changing_src:test.checksums replicate:test.checksums bidirectional:0 pid:41650 user:root host:localhost.localdomain*/"] at line 10707 while doing check_sum.test1 on 192.168.1.129
看到报错了吧,提示admin用户没有INSERT、DELETE权限(如果是root用户,就没这些小问题),在master授权admin用户权限后再执行如下命令(master操作):
[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --execute [root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T17:57:18 0 0 3 1 0 0.073 check_sum.test1
可以看到再次检查的时候,DIFFS已经是0了,去slave查看一下表的数据(slave操作):
mysql> select * from check_sum.test1; +----+-------+ | id | couse | +----+-------+ | 1 | aa | | 2 | bb | | 3 | cc | +----+-------+ 3 rows in set (0.00 sec)
已经跟master上的数据一致了。
第二种情况:(slave的端口不是3306,则要用另一种方式去检查)
环境:192.168.1.128:3306(master)
192.168.1.129:3307(slave)
执行数据检查命令pt-table-checksum:
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 Cannot connect to P=3306,h=192.168.1.129,p=...,u=admin Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information. TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T19:59:11 0 0 3 1 0 0.065 check_sum.test1
以上报错了,因为pt-table-checksum默认是找slave库的3306,现在slave上的端口是3307了(在master操作):
mysql> show slave hosts; +-----------+---------------+------+-----------+ | Server_id | Host | Port | Master_id | +-----------+---------------+------+-----------+ | 11 | 192.168.1.129 | 3307 | 1 | +-----------+---------------+------+-----------+ 1 row in set (0.00 sec) mysql>
在master上test库上创建一个表:
mysql> use test Database changed mysql> CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); Query OK, 0 rows affected (0.08 sec) mysql>
写入从库信息,如果有多个从库,就插入多条记录:
mysql> INSERT INTO dsns (parent_id,dsn) values(1, "h=192.168.1.129,u=admin,p=123456,P=3307"); Query OK, 1 row affected (0.04 sec) mysql> select * from dsns; +----+-----------+-----------------------------------------+ | id | parent_id | dsn | +----+-----------+-----------------------------------------+ | 1 | 1 | h=192.168.1.129,u=admin,p=123456,P=3307 | +----+-----------+-----------------------------------------+ 1 row in set (0.00 sec)
然后在master上执行数据校验命令:
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306--recursion-method=dsn=h=192.168.1.128,
D=test,t=dsns
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T20:10:30 0 0 3 1 0 0.100 check_sum.test1
在slave库执行删除数据操作:
mysql> select * from test1; +----+-------+ | id | couse | +----+-------+ | 1 | aa | | 2 | bb | | 3 | cc | +----+-------+ 3 rows in set (0.00 sec) mysql> delete from test1 where id=3; Query OK, 1 row affected (0.00 sec)
再在master库执行数据校验命令:
[root ~]$ pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum h=192.168.1.128,u=admin,p=123456,P=3306 --recursion-method=dsn=h=192.168.1.128, D=test,t=dsns TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T20:25:42 0 1 3 1 0 0.020 check_sum.test1
已经检查出数据不一致了,至于怎么把数据同步到从库,还没研究出来,按第一种方法,再换一下端口,也不行,因为pt-table-sync默认找3306端口,如果你研究出来了,分享下哈,哈哈^.^
总结:pt-table-checksum和pt-table-sync工具是非常好用的数据检查及修复的工具,在日常生活中会经常用到,可以写脚本去监控数据的一致性
参考资料:http://www.percona.com/doc/percona-toolkit/2.2/pt-table-checksum.html
http://www.percona.com/doc/percona-toolkit/2.2/pt-table-sync.html
http://keithlan.github.io/2016/05/25/pt_table_checksum/
作者:陆炫志 出处:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111 您的支持是对博主最大的鼓励,感谢您的认真阅读。本文版权归作者所有,欢迎转载,但请保留该声明。 |