pt-table-checksum 是 Percona Toolkit 里最具代表性的“在线主从一致性校验”工具,也是 MySQL DBA 工具箱中出场率最高的脚本之一。它能够在业务持续写入、复制链路正常工作的前提下,对 5.6/5.7/8.0 各版本做成千上万张表、百亿级行数据进行“分块-校验-对比”,并精确定位到哪个库、哪张表、哪个 chunk 出现了不一致,而不阻塞线上事务,也不产生明显复制延迟。以下从背景、原理、核心特性、使用流程、参数精讲、常见案例、避坑指南、自动化落地八个维度,对 pt-table-checksum 进行系统梳理,帮助你在生产环境“敢用、会用、用好”。
## 一、诞生背景
MySQL 主从复制基于 binlog 逻辑重放,只能保证“事件”层面的同步,不能保证“数据”层面的逐字节一致。网络丢包、磁盘静默损坏、BUG 导致写入过滤、人为在从库执行 DML、row 模式与 statement 混用等情况,都可能让主从数据悄然分叉。传统的“停服→mysqldump→diff”方案需要停机,对 7×24 业务不可接受;而逐行对比又面临大表内存爆炸、锁表、延迟飙高等问题。pt-table-checksum 通过“分块 checksum + 复制链路同步对比”的思路,把校验成本均摊到若干秒级的小查询上,实现在线、低侵入、可中断、可并行的一致性检查。
## 二、核心原理
1. 单行校验值:工具先把每列 CAST 成字符串,再用 CONCAT_WS() 拼成一行,最后计算 CRC32,得到行级校验和。
2. 分块校验值:基于主键或唯一索引,把表切成若干“chunk”(默认目标 0.5 s 执行完毕)。对块内所有行的 CRC32 做 BIT_XOR 聚合,得到块级校验和;同时记录块内行数 this_cnt。
3. 主库写结果:将 db、tbl、chunk 号、master_cnt、master_crc 写入校验表 percona.checksums;该表必须提前存在,并随 binlog 复制到从库。
4. 从库复算:从库收到同一块的 SQL 后,本地重算 cnt 与 crc,并 UPDATE 同一行记录,填充 this_cnt、this_crc。
5. 差异对比:工具在主库 SELECT percona.checksums,若 master_crc ≠ this_crc 或 master_cnt ≠ this_cnt,即认定该块不一致,EXIT STATUS 置非 0,并在标准输出打印 DIFF 标记。
6. 并发安全:每个 chunk 计算前加 FOR UPDATE 范围锁,锁区间仅覆盖本块索引间隙;事务隔离级别为 REPEATABLE READ,确保快照一致性;同时监控从库复制延迟,若延迟>阈值则自动 sleep,防止校验把从库拖垮。
## 三、关键特性
- 在线:对 InnoDB 仅行级间隙锁,对业务 DML 几乎无阻塞。
- 自适应:根据实际执行时间动态调整 chunk 大小,负载高时自动“细嚼慢咽”。
- 可中断:Ctrl-C 后重新执行,可自动跳过已正确完成的 chunk。
- 并行:同时开启多张表校验,支持 --max-load/–critical-load 自动限流。
- 精准:能定位到 chunk 粒度,再借助 pt-table-sync 可生成修复 SQL。
- 安全:默认拒绝在存在 replicate-wild-do/ignore 或 binlog_format=ROW 的实例运行,防止校验语句被过滤或语义不符。
## 四、标准使用流程
1. 创建账号
```sql
GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.*
TO 'checksum'@'10.%' IDENTIFIED BY 'xxx';
GRANT INSERT, UPDATE, DELETE ON percona.* TO 'checksum'@'10.%';
```
2. 建校验表
```sql
CREATE DATABASE IF NOT EXISTS percona;
CREATE TABLE percona.checksums (
db char(64) NOT NULL,
tbl char(64) NOT NULL,
chunk int NOT NULL,
chunk_time float NULL,
rowcount bigint NULL,
this_crc char(40) NULL,
this_cnt bigint NULL,
master_crc char(40) NULL,
master_cnt bigint NULL,
ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (db,tbl,chunk)
);
```
3. 执行校验
```bash
pt-table-checksum \
h='master.ip',P=3306,u='checksum',p='xxx' \
--replicate=percona.checksums \
--no-check-binlog-format \
--recursion-method=hosts \
--max-load Threads_running=50 \
--max-lag 5 \
--chunk-time 0.5 \
--progress time,30 \
--create-replicate-table \
--databases db1,db2 \
--tables user,order
```
4. 查看差异
```sql
SELECT db, tbl, chunk, master_cnt, this_cnt, master_crc, this_crc
FROM percona.checksums
WHERE (master_cnt <> this_cnt OR master_crc <> this_crc OR
ISNULL(master_crc) <> ISNULL(this_crc));
```
5. 修复(可选)
```bash
pt-table-sync \
h='master.ip',P=3306,u='checksum',p='xxx' \
--replicate percona.checksums \
--sync-to-master --print > fix.sql
```
人工 review 后 source 进主库,再通过复制重放即可。
## 五、参数精讲
- `--chunk-time`:目标执行时长,默认 0.5 s;值越大 IO 次数越少,但锁范围更大。
- `--chunk-size-limit`:限制最大 chunk 行数,防止主键稀疏时一次拉取过多。
- `--max-lag`:允许从库最大延迟秒数,超则暂停。
- `--max-load/critical-load`:根据 Threads_running/Threads_connected 自动限流。
- `--recursion-method`:发现从库方式;hosts 表、dsn 表、processlist 或 cluster 模式,多从库环境建议写入 percona.dsn 表避免漏检。
- `--ignore-databases/tables`:跳过无需校验的库表,常用于日志类、临时表。
- `--resume`:断点续跑;与 --pid 配合使用可做定时任务幂等。
- `--set-vars`:自动设置 SQL 变量,如 `innodb_lock_wait_timeout=10,lock_wait_timeout=10`。
## 六、典型实战
1. 数据迁移后的“体检”
全库导入新从库后,先开启 pt-table-checksum 全量校验,确认 0 DIFF 再切换读流量。
2. 深夜批量修复
发现备份从库与主库不一致,白天业务高峰不敢动;凌晨 2 点用 pt-table-sync 生成修复 SQL,10 分钟完成补洞。
3. 灰度双写验证
业务侧做“新老库”双写,利用 pt-table-checksum 比对新库与主库差异,达到 0 DIFF 后正式切流。
4. 自动化巡检
将校验封装成 Jenkins 任务,每周日凌晨执行;若 EXIT STATUS≠0 则飞书告警,并自动输出 DIFF 报表。
## 七、避坑指南
- 表无主键或唯一索引:工具会退化为单 chunk 全表扫描,锁全表且耗时高,务必先加索引。
- 使用 ROW 格式:默认拒绝执行,需要 --no-check-binlog-format,但需确保 replicate-*-do/ignore 规则不会过滤掉校验表。
- 从库过滤: replicate-wild-ignore-db=mysql 导致 percona.checksums 被忽略,结果永远 0 DIFF;可把 checksums 表放业务库或调整过滤规则。
- 字符集与排序规则不一致:主从列定义不同会导致 CONCAT_WS 结果不同,出现伪 DIFF;要先通过 ALTER 统一。
- 大字段:BLOB/TEXT 列默认被工具跳过(长度超长),若业务需要校验,可调整 --chunk-size-limit 和 --binary-mod 参数。
- 长事务:校验过程中如果块范围被未提交事务持有间隙锁,会触发 InnoDB lock wait timeout;建议调大 --set-vars 中的超时时间,或避开批量更新窗口。
## 八、自动化落地示例
以下脚本结合 systemd-timer 或 crontab,可实现“周期巡检+失败自报警+修复建议”:
```bash
#!/bin/bash
DSN="h=127.0.0.1,P=3306,u=checksum,p=xxx"
LOG=/var/log/pt-checksum.log
OPTS="--replicate=percona.checksums --no-check-binlog-format --recursion-method hosts --max-lag 5 --chunk-time 0.5"
pt-table-checksum $DSN $OPTS --quiet --resume >> $LOG 2>&1
RET=$?
if [ $RET -ne 0 ]; then
DIFF_SQL="SELECT db,tbl,SUM(this_cnt) total_rows,COUNT(*) chunks \
FROM percona.checksums \
WHERE (master_cnt<>this_cnt OR master_crc<>this_crc) \
GROUP BY db,tbl;"
mysql -BNe "$DIFF_SQL" | mail -s "MySQL 主从不一致" dba@company.com
fi
```
## 总结
pt-table-checksum 通过“分块 checksum + 复制链路同步对比”的精巧设计,兼顾了准确性、低侵入性与可扩展性,已成为 MySQL 生态数据一致性检查的“黄金标准”。掌握其原理与参数后,可在数据迁移、故障恢复、灰度双写、定期巡检等多种场景下快速发现主从不一致,并配合 pt-table-sync 精准修复,真正把“数据质量”掌握在自己手中。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




