pt-table-checksum是目前能够说是最好的查看主从一致性的工具html
先来个使用例子,有助快速上手使用mysql
在主库执行: mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE,CREATE,DELETE,INSERT,UPDATE ON *.* TO 'USER'@'MASTER_HOST' identified by 'PASSWORD';
注:建立用户,这些权限都是必须的,不然后续执行时会报错,固然,若是不想授予这么多权限,那就须要把权限对应的活先本身干了或者直接在命令行指定,好比若是不想设create权限的话,须要本身指定库和表(具体参看下面的参数介绍:--replicate)
shell> ./pt-table-checksum --host='master_host' --user='user' --password='password' --port='port' --databases=databases --tables=tables --recursion-method=processlist
注: (1)在有些状况下,recursion-method若是不设会报错:Diffs cannot be detected because no slaves were found. 其参数有四:processlist/hosts/dsn=DSN/no,用来决定查找slave的方式是show full processlist仍是show slave hosts仍是命令行直接指定仍是压根就不许备找从库,具体见下面参数介绍
(2)主从的端口必须一致,若是不一致就须要用DSN方法进行指定,不然会报找不到从库的错误,若是能连到从库服务器但没有指定端口,默认会寻找3306端口
(3)被检查的主从binlog_format必须为statement,若是不是statement-based,那就添加参数--no-check-binlog-format来避开binlog格式检查
(4)检查结果会输出到默认创建的percona库中的checksums表中,并会输出统计信息到屏幕,diffs列展现主从数据不一致的块的数目,若是都是0,恭喜,数据是一致的
一. 运行原理算法
pt-table-checksum运行在主库上,经过show processlist或show slave hosts或DSN方式来肯定从库并链接,默认使用crc32算法来进行数据校验,该工具之因此须要把binlog设置为statement格式,是由于该工具能得出主从是否一致所依赖的就是statement基础上一样的SQL语句在主从库上各自的执行结果,主库进行检查后sql语句传给从库,从库执行一遍后,也获得本身的结果,执行语句是:sql
SELECT COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', 各类列名)) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `database`.`table` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000'))
注: where的条件是根据系统繁忙程度计算出的要执行的范围
cnt是目前检查的块包括的行数,unsigned是计算出的该块数据的校验值shell
若是主库和从库得出的这两个值都是同样的,那数据就是一致的,若是不同,那就主从不一致,固然,字符集、浮点数之类的问题须要提早规避,以避免错判数据库
工具将主从各自获得的结果处理后放到checksums表中并呈现一些结果在屏幕输出中,work over安全
二. 安全性保障服务器
pt-table-checksum采用了不少措施来保证检查过程当中的安全性,默认参数是能够保障使用安全的,不过参数能够配置,因此须要详细了解参数的功能后再进行更改,不然最好采用默认
socket
先了解一下工具在执行过程当中作了些什么:ide
主库
SET SESSION innodb_lock_wait_timeout=1 /*只针对innodb表*/
SET SESSION wait_timeout=10000
SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION'
SET @@binlog_format = 'STATEMENT'
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
SET @@SQL_QUOTE_SHOW_CREATE = 1 /*保证检查安全的相关设置*/
CREATE DATABASE IF NOT EXISTS `percona`
CREATE TABLE IF NOT EXISTS `percona`.`checksums` /*建立校验值存放的库和表*/
SHOW GLOBAL STATUS LIKE 'Threads_running' /*检查系统运行状况*/
SHOW DATABASES
SHOW TABLES FROM `database`
USE `database`
SHOW CREATE TABLE `database`.`a`
EXPLAIN SELECT * FROM `database`.`a` WHERE 1=1
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `database`.`a` FORCE INDEX(`PRIMARY`) ORDER BY `id` LIMIT 1 /*first lower boundary*/
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `database`.`a` FORCE INDEX (`PRIMARY`) WHERE `id` IS NOT NULL ORDER BY `id` LIMIT 1 /*key_len*/
EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ * FROM `database`.`a` FORCE INDEX (`PRIMARY`) WHERE `id` >= '1' /*key_len*/
/*每次用use database来肯定数据库并依次只选择一个表进行详细数据量分析*/
USE `percona`
DELETE FROM `percona`.`checksums` WHERE db = 'database' AND tbl = 'a'
/*避免以前有过检查并保存有该表的检查信息,将对应信息删掉*/
USE `database`
EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `database`.`a` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `database`.`a` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/
/*每次检查表时,第一个块的行数固定为1000,以后会根据系统繁忙程度计算出在规定时间内能处理的行数来肯定为一个chunk,默认时间为0.5秒,能够更改*/
EXPLAIN SELECT COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, `name`, `type`)) AS UNSIGNED)), 10, 16)), 0) AS crc
FROM `database`.`a` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) /*explain checksum chunk*/
REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT 'database', 'a', '1', '
PRIMARY', '1', '1000', COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, `name`, `type`)) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `database`.`a` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) /*checksum chunk*/
/*explain下肯定下执行计划,而后开始真正的checksum工做,是用 REPLACE..SELECT语句计算数据状况并将结果插入到checksums表中*/
SHOW WARNINGS
UPDATE `percona`.`checksums` SET chunk_time = '0.003725', master_crc = 'a9bd6d97', master_cnt = '1000' WHERE db = 'database' AND tbl = 'a' AND chunk='1'
/*检查是否有警告,进一步完善checksums表中的检查信息*/
一个块的检查结束,开始下一个块或下一个表
从库
跟主库相似,少了一些设置及explain过程,但多了一个show slave status的检查,来辅助工具判断从库链接和延迟等状况,来肯定检查是否继续,暂停仍是退出
全部检查执行完后会有这样一个语句来报出检查结果
SELECT CONCAT(db, '.', tbl) AS `table`, chunk, chunk_index, lower_boundary, upper_boundary, COALESCE(this_cnt-master_cnt, 0) AS cnt_diff, COALESCE(this_crc <> master_crc OR ISNULL(master_crc) <> ISNULL(this_crc), 0) AS crc_diff, this_cnt, master_cnt, this_crc, master_crc FROM `percona`.`checksums` WHERE (master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc)) AND (db='database' AND tbl='a')
pt-table-checksum一次只针对一个表,并且会根据表的大小以及当前系统的繁忙程度,计算出一次检查中能包含的数据行数,来尽可能避免对线上服务的影响,若是在执行过程当中遇到突发的负载增长,还会自动的将检查停下来等待,因此即便面对成千上万的数据库和表时,它也能顺利的进行检查
在检查过程当中,工具会随时对主从链接状况进行检查,若是从库延迟太大,主从复制中断,检查会停下来等待;这里须要注意的是主从复制过滤,由于这种情形下,主从数据库中的库表存在状况不一致,检查过程当中的执行语句会与当前的主从复制过程冲突致使主从复制进程失败,因此若是有过滤存在,须要指定参数--no-check-replication-filters
在一个块的数据被检查以前,会先执行explain操做,来肯定执行该检查的安全性,若是太大不能在指定时间内完成检查的话就会将该块数据跳过,另外,若是主库上整表的数据特别少或干脆是空表,并不会直接将整表当作一个块去检查,而是会再去从库,肯定从库中也是有一样少的数据,避免从库表数据太多却被当成一个块执行形成的从库数据阻塞
另外还有一些安全保护设置,在上面的执行流程中已经列出来了,如设置innodb_lock_wait_timeout=1,若是锁等待超过1S,就放弃这次执行
在执行过程当中若是遇到任何异常,可随时中断进程,如kill或CTRL-C,不会形成任何影响,后面想今后次中断继续检查时,简单的采用--resume就能够
三. 参数介绍
1. 链接主从库的参数:
--host --socket --user --password --pid --port
2. 肯定比较范围的参数
(1) 指定库
--databases / --ignore-databases 要比较的库 / 比较过程当中忽略这些库
--databases-regex / --ignore-databases-regex 同上,不过能够用正则匹配
(2) 指定表
--tables / --ignore-tables 要比较的表 / 比较过程当中忽略这些表
--tables-regex / --ignore-tables-regex 同上,不过能够用正则匹配
(3) 指定列
--columns / --ignore-columns 要比较的列 / 比较过程当中忽略这些列
(4) 直接指定表范围
--where 直接指定表中要比较的范围
(5) 根据引擎选表
--engines / --ignore-engines 比较指定的引擎表 / 比较过程当中忽略含有这些引擎的表
3. 指定链接中断后行为的参数
--resume 若是主从一致性检查中途中断的话,能够用这个参数来使工具从上次中断时检查的最后一个表开始继续检查
--retries 若是在检查过程当中有非致命性的中断的话,如被kill或者从库延迟等,指定该参数后,工具会自动尝试重连
4. 需重点关注的参数
(1) --[no]check-binlog-format
默认会检查binlog-format,若是不是statment,就会报错退出,想避免该检查能够设置--no-check-binlog-format
(2) --recursion-method
参数有四:processlist/hosts/dsn=DSN/no,默认是processlist,hosts,但最好仍是指定一下,建议指定--recursion-method=processlist,no通常不使用
dsn=DSN方法使用时,须要先去库里建立一个表,好比在percona库中建一个dnsn表
建表语句是:
CREATE TABLE `dsns` (`id` int(11) NOT NULL AUTO_INCREMENT,`parent_id` int(11) DEFAULT NULL,`dsn` varchar(255) NOT NULL,PRIMARY KEY (`id`));
建好后插入主从复制信息数据,如:insert into table dsns(dsn) values(h=slave_host,u=repl_user,p=repl_password,P=port );
而后就可使用DSN方法了:命令为:--recursion-method dsn=D=percona,t=dsns.
(3) --replicate
用来指定存放计算结果的表名, 默认是percona.checksums,工具会默认自动建立库percona和表checksums并将checksum的检查结果输入到这个表中,若是本身用该参数去指定表的话,表结构必须是:
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, PRIMARY KEY (db, tbl, chunk), INDEX ts_db_tbl (ts, db, tbl) ) ENGINE=InnoDB;
须要注意的是存储引擎设置,若是检查的表是innodb表,就设置innodb引擎,若是检查的表和checksums表的引擎不一致,如分别是myisam和innodb,会引发复制错误:“different error on master and slave.”!!!
5. 其余部分参数详述:
(1) --[no]check-replication-filters
默认在检查到在主从复制过程当中有被用..ignore..过滤掉的表,检查会中断并退出,若是想避开这个检查能够设置--no-check-replication-filters
(2) --chunk-index(type: string)
工具默认在分块时会选取最合适的索引来explain肯定chunk的大小,但若是你但愿用其余索引来执行,能够用该参数来指定,工具会以FORCE INDEX的形式把指定的索引加进去
(3) --chunk-index-columns(type: int)
能够用来指定组合索引中使用前几个列来辅助分块
(4) --chunk-size
直接肯定chunk的大小,默认1000行数据,但不建议使用,建议使用--chunk-time代替
(5) --chunk-time
默认是0.5秒,工具会根据当前系统运行繁忙程度计算出在该指定时间内能够处理的数据行数(即chunk),比较灵活
(6) --[no]empty-replicate-table
默认yes,每次检查表以前都去把checksums表中已有的该表信息删掉,以利于后续从新插入新检查信息
(7) --float-precision(type: int)
设置浮点数的四舍五入方式,以免不一样版本间或其余特定状况中,主从间因浮点数四舍五入的方式不一样而致使查出不一致,If you specify a value of 2, for example, then the values 1.008 and 1.009 will be rounded to 1.01, and will checksum as equal
(8) --function
计算checksum值时的函数,默认是CRC32,其余还有FNV1A_64, MURMUR_HASH, SHA1, MD5等
(9) --max-lag
默认1S,主从最大延迟,超过这个延迟时间,就会停下来等待从库同步,肯定方法是采用Seconds_Behind_Master的值
(10) --progress
指定后能够按设定的参数将执行过程当中的运行状况输出到STDERR,如主从延迟时从库的等待,等待时间等,指定时后跟两个参数值,默认是 "time,30",前一个参数有:percentage, time, or iterations;后一个指定百分比,具体时间或者间隔的数目
四. 结果分析
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 10-20T08:36:50 0 0 200 1 0 0.005 db1.tbl1 10-20T08:36:50 0 0 603 7 0 0.035 db1.tbl2 10-20T08:36:50 0 0 16 1 0 0.003 db2.tbl3 10-20T08:36:50 0 0 600 6 0 0.024 db2.tbl4
TS The timestamp (without the year) when the tool finished checksumming the table. ERRORS The number of errors and warnings that occurred while checksumming the table. Errors and warnings are printed to standard error while the table is in progress. DIFFS The number of chunks that differ from the master on one or more replicas. If --no-replicate-check is specified, this column will always have zeros. If --replicate-check-only is specified, then only tables with differences are printed. ROWS The number of rows selected and checksummed from the table. It might be different from the number of rows in the table if you use the –where option. CHUNKS The number of chunks into which the table was divided. SKIPPED The number of chunks that were skipped due to errors or warnings, or because they were oversized. TIME The time elapsed while checksumming the table. TABLE The database and table that was checksummed.