Mysql的复制是通过传输binlog来实现,是一种逻辑复制,然而这种复制方式也带来了主从不一致的风险。因此主从不一致的校验对一个DBA来说是至关重要的。percona的pt-table-checksum一直作为主从不一致校验的热门工具,让我们现在来一起了解他吧。
pt-table-checksum通过sql在主库执行数据块的校验,然后把相同的语句传送到从库,并在从库上计算数据块的校验,最后将主从库相同块的校验值进行对比,辨别主从不一致。
一、事例
pt-table-checksum --nocheck-replication-filters--no-check-binlog-format --replicate=test.checksum --databases=freedomh=127.0.0.1,u=root,P=3301 --tables=a1--chunk_size=100
装完pt工具后,运行其中的pt-table-checksum。
nocheck-replication-filters:不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。
--no-check-binlog-format : 不检查复制的binlog模式,要是binlog模式是ROW,
--replicate校验表
--databases �Ctables 所需检查的数据库名和表名
--chunk_size 块大小定义(即一个块包含的行数)
二、内部工作重要过程
1. SET @@binlog_format := 'STATEMENT'
创建校验信息存放表
SET SESSION TRANSACTIONISOLATION LEVEL REPEATABLE READ
查找表的索引列
确定分块的第一行,和分块的最后行索引数值
查出该块的所有记录,并且做校验,最后插入检验表
查出主库校验值和校验行数更新到校验信息表的master_crc, master_cnt列,执行下一个块回到步骤5
通过sql命令查出校验表中主从校验不一致的信息。
详解:
pt-table-checksum是通过相同sql在主从库进行计算而校验出来的,所以需要将binlog格式需改成STATEMENT。
3.修改隔离级别,通过加锁保证在取数据行数(replaceinto select from )到计算出检验值这段时间数据不会被修改。他采用块,来减少每次锁住数据的行数,这样提高了并发性。
查出分块区间。首先判断是否为第一个块,如果是的话查找第一个索引值,然后根据第一个索引值查出该快最后个索引值。如果不是第一个块,根据上个块的最后个索引值作为标准,查出该块的第一个索引和最后个索引。
第1个块:
SELECT id` FROM `freedom`.`a1` FORCE INDEX(`PRIMARY`) WHERE `id` IS NOT NULL ORDER BY `id` LIMIT1
先根据表a1的主键索引排序,然后得到第一个索引值。
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM`freedom`.`a1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id`LIMIT 100, 2
因为块数大小为100,查出该块中最后个索引值的大小。
第2个块:
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM`freedom`.`a1` FORCE INDEX(`PRIMARY`) WHERE ((`id` > '100')) ORDER BY `id`LIMIT 101, 2
上个块的最后个索引值为100,查出其后的100个索引值,得到该快的第一个索引和最后个索引。
6.计算校验值
先根据该块的索引区间,将该块所有行数据进行合并然后做校验,然后插入检验表。插入检验表的信息有,数据库名,表名,块号,第一个索引,最后个索引,块的行数以及块的内容。
7. 将主库的校验值更新到主从校验表。
UPDATE `test`.`checksum` SET chunk_time ='0.002492', master_crc = 'd7ac8fcb', master_cnt = '100' WHERE db = 'freedom'AND tbl = 'a1' AND chunk = '1'
将主库的校验值更新到主从校验表。
9. 在从库检查主从不同步。
select * from test.checksums where master_cnt <>this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <>ISNULL(this_crc) \G
查出检验位或行数不同的数据
三、性能影响
数据库层面:并发性上,通过块来大大减少锁的影响,从而又能保证数据一致性又能保证检验数据的准确性。主从延迟问题上,因为主库更新可以并发,然而从库Slave_SQL_Running线程是单线程这种速率差异将会导致一个时间段中主从数据不一致,这样将导致检验数据不准确,主库执行sql检验语句再通过复制原理最后从库再执行sql语句,虽然主从执行校验的时间不同但保证了数据的一致性。主从不一致过大,也可以通过限速选项来避免。
服务器层面:从图表可以看到因为大量计算校验值,cpu消耗量较大。可以通过减少块数的大小来减轻cpu的负载,但需要增加处理时间。IO,每个块需要读操作做一次以及写操作两次,对于IO的负载是比较低的。
1G数据 200W条数据量 | |||
块数大小 | CPU(%) | IO(%) | 处理时间(分钟) |
1000 | 45 |
7 |
1 |
100 | 28 | 7 | 4 |
四、注意事项
1.从库配置表上需要加上,
report_host=slave_ip
report_port=slave_port
不然将报Diffscannot be detected because no slaves were found.错误
2.表中没有索引,pt-table-checksum将没办法处理
3.表中只有普通索引。当数据列有重复并且正好在分块的交界中,将会报错。所以表中最好有一个唯一索引列。
01-07T12:05:29 Error checksumming tablefreedom.a6: Possible infinite loop detected! The lower boundary for chunk 2 is <cc, cc> and the lower boundaryfor chunk 3 is also <cc, cc>. Thisusually happens when using a non-unique single column index. The current chunk index for table freedom.a6is name which is not unique and covers 1 colum
4.块的定义过大。当块大于表的行数时,将会产生全表锁。