如何通过配置MySQL使用pt-table-checksum进行主备数据校验?
- 内容介绍
- 文章标签
- 相关推荐
本文共计924个文字,预计阅读时间需要4分钟。
连不上数据库基本是权限或网络问题,不是工具本身故障。它默认使用 root@localhost 连接,但生产环境通常禁用 root 本地登录,也很少开放远程 root 登录。
- 必须创建专用校验账号,且需
REPLICATION CLIENT、PROCESS、SELECT权限,缺一不可;SHOW DATABASES有时也要(取决于是否跨库) - 连接串里别漏
--host和--port,尤其是主库监听非 3306 端口时,不显式指定会连 localhost:3306 - 如果报
Access denied for user,先用 mysql 命令行手动试:mysql -u checksum_user -p -h 主库IP -P 3307,确认基础连通性
校验时主库 CPU 或从库延迟飙升
pt-table-checksum 默认对每张表逐块计算 CRC32,加锁读+全表扫描,对大表就是灾难。它不是“无感”工具,而是“可控干扰”工具。
- 务必加
--chunk-size-limit 2.0(默认 4.0),避免单 chunk 太大导致锁太久 - 用
--max-load="Threads_running=25"主动退避,别等主库卡死才停;值按你主库常态Threads_running的 1.5 倍设 - 跳过日志表、临时统计表:加
--ignore-databases=mysql,information_schema和--ignore-tables=app.log_202406 - 不要在业务高峰跑,哪怕加了限流,IO 和 buffer pool 冲击仍明显
从库没报错但 checksum 结果显示不一致
结果不一致 ≠ 数据真不同,更可能是从库延迟未追平、或者 binlog 格式/设置导致校验值计算路径不一致。
- 先确认从库
Seconds_Behind_Master = 0且Slave_SQL_Running = Yes;否则 checksum 读的是从库旧快照 - 检查主从
binlog_format是否都是ROW;若主为MIXED或STATEMENT,某些函数(如NOW()、UUID())在从库重放时值不同,CRC 必然不等 - 校验表必须有主键或唯一索引,否则 pt-table-checksum 无法分块,会退化成全表锁+全扫,且结果不可靠
- 运行后查
percona.checksums表,看diff_cnt > 0的行,再用pt-table-sync --print对比具体差异行
pt-table-sync 同步前必须手动验证
pt-table-sync 是把双刃剑:它能修数据,也能把主库删干净——尤其当主从角色误判时。
- 永远先加
--print,看它打算执行哪些REPLACE或DELETE;输出里出现DELETE FROM `db`.`t` WHERE ...就要立刻停下 - 必须显式指定
--sync-to-master(从库上运行)或--replicate(配合 checksums 表),不写清楚方向就容易反向同步 - 涉及大表时,
--chunk-index要指定最合适的索引,否则生成的 SQL 可能全表扫描,同步过程比校验还慢 - 线上环境禁止直接
--execute,至少先在从库副本上--dry-run+--print走一遍完整流程
真正难的不是跑通命令,而是判断哪一行 diff 是复制延迟导致的假阳性,哪一行是主库被误更新造成的真异常——这得结合 binlog 解析和业务操作时间点交叉验证,工具只给线索,不替你下结论。
本文共计924个文字,预计阅读时间需要4分钟。
连不上数据库基本是权限或网络问题,不是工具本身故障。它默认使用 root@localhost 连接,但生产环境通常禁用 root 本地登录,也很少开放远程 root 登录。
- 必须创建专用校验账号,且需
REPLICATION CLIENT、PROCESS、SELECT权限,缺一不可;SHOW DATABASES有时也要(取决于是否跨库) - 连接串里别漏
--host和--port,尤其是主库监听非 3306 端口时,不显式指定会连 localhost:3306 - 如果报
Access denied for user,先用 mysql 命令行手动试:mysql -u checksum_user -p -h 主库IP -P 3307,确认基础连通性
校验时主库 CPU 或从库延迟飙升
pt-table-checksum 默认对每张表逐块计算 CRC32,加锁读+全表扫描,对大表就是灾难。它不是“无感”工具,而是“可控干扰”工具。
- 务必加
--chunk-size-limit 2.0(默认 4.0),避免单 chunk 太大导致锁太久 - 用
--max-load="Threads_running=25"主动退避,别等主库卡死才停;值按你主库常态Threads_running的 1.5 倍设 - 跳过日志表、临时统计表:加
--ignore-databases=mysql,information_schema和--ignore-tables=app.log_202406 - 不要在业务高峰跑,哪怕加了限流,IO 和 buffer pool 冲击仍明显
从库没报错但 checksum 结果显示不一致
结果不一致 ≠ 数据真不同,更可能是从库延迟未追平、或者 binlog 格式/设置导致校验值计算路径不一致。
- 先确认从库
Seconds_Behind_Master = 0且Slave_SQL_Running = Yes;否则 checksum 读的是从库旧快照 - 检查主从
binlog_format是否都是ROW;若主为MIXED或STATEMENT,某些函数(如NOW()、UUID())在从库重放时值不同,CRC 必然不等 - 校验表必须有主键或唯一索引,否则 pt-table-checksum 无法分块,会退化成全表锁+全扫,且结果不可靠
- 运行后查
percona.checksums表,看diff_cnt > 0的行,再用pt-table-sync --print对比具体差异行
pt-table-sync 同步前必须手动验证
pt-table-sync 是把双刃剑:它能修数据,也能把主库删干净——尤其当主从角色误判时。
- 永远先加
--print,看它打算执行哪些REPLACE或DELETE;输出里出现DELETE FROM `db`.`t` WHERE ...就要立刻停下 - 必须显式指定
--sync-to-master(从库上运行)或--replicate(配合 checksums 表),不写清楚方向就容易反向同步 - 涉及大表时,
--chunk-index要指定最合适的索引,否则生成的 SQL 可能全表扫描,同步过程比校验还慢 - 线上环境禁止直接
--execute,至少先在从库副本上--dry-run+--print走一遍完整流程
真正难的不是跑通命令,而是判断哪一行 diff 是复制延迟导致的假阳性,哪一行是主库被误更新造成的真异常——这得结合 binlog 解析和业务操作时间点交叉验证,工具只给线索,不替你下结论。

