一. 运行原理
pt-table-checksum运行在主库上,通过show processlist或show slave hosts或DSN方式来确定从库并连接,默认使用crc32算法来进行数据校验,该工具之所以需要把binlog设置为statement格式,是因为该工具能得出主从是否一致所依赖的就是statement基础上同样的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是计算出的该块数据的校验值
如果主库和从库得出的这两个值都是一样的,那数据就是一致的,如果不一样,那就主从不一致,当然,字符集、浮点数之类的问题需要提前规避,以免错判
工具将主从各自得到的结果处理后放到checksums表中并呈现一些结果在屏幕输出中,work over
二. 安全性保障
pt-table-checksum采用了很多措施来保证检查过程中的安全性,默认参数是可以保障使用安全的,不过参数可以配置,所以需要详细了解参数的功能后再进行更改,否则最好采用默认
先了解一下工具在执行过程中做了些什么:
主库
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就可以
三. 参数介绍
--host --socket --user --password --pid --port
(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 比较指定的引擎表 / 比较过程中忽略含有这些引擎的表
--resume 如果主从一致性检查中途中断的话,可以用这个参数来使工具从上次中断时检查的最后一个表开始继续检查
--retries 如果在检查过程中有非致命性的中断的话,如被kill或者从库延迟等,指定该参数后,工具会自动尝试重连
(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.”!!!
(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.
复制代码
原文地址:http://blog.51cto.com/zhongliang/2095650