编程 pt-table-sync 修复侧:先 --dry-run --print,再决定改源还是改副本

2026-10-31 00:05:03

pt-table-sync 修复侧:先 --dry-run --print,再决定改源还是改副本

工具文档:pt-table-sync。本文不讨论差异怎么算出来;比对侧看 pt-table-checksum。

pt-table-sync 会直接写数据。它成熟、久经生产,但用错方向时,代价是改坏源库。下面只讲修复侧:什么时候允许改、改在哪一端、哪些开关是红线。

一、默认只打印,--execute 才落笔

不带 --execute 时,工具只做分析并打印,不写库。但“安全上线”不止这一步,固定走两步:

pt-table-sync --dry-run --print \
  --replicate percona.checksum \
  h=source1 \
  > /tmp/sync-preview.sql

--dry-run 表示只分析不执行,--print 打出真正会跑的 SQL。两者一起用,才看得到“将要发出什么语句”。确认语句形态和影响面符合预期后,再加 --execute。

--print 只打同步语句;如果想看选 chunk / nibble / row 的 SQL,需要 --print 配合两次 --verbose,输出量会很大。

文档的原始要求是:读文档、看 BUGS、非生产环境先测、生产先备份并验证备份。这不是客套话,因为 --execute 写下去就是真实数据。

二、--replicate 模式:只改有差异的 chunk

--replicate 指向 pt-table-checksum 用自身 --replicate 写出的结果表。工具读这张表,只修 checksum 判定为有差异的 chunk。这是最可控的路径——修什么由比对结果决定,而不是工具现场去猜。

pt-table-sync --execute --replicate percona.checksum h=source1

不带 --replicate 时,工具自己在两端找差异。此时命令行 DSN 的语义是严格的:第一个 DSN 是源,后面的是目的地;目的地可以有一个或多个,但必须与源相互独立,不能处于同一复制拓扑。工具一旦发现目的地是副本就会报错退出——它是直接往目的地写数据的,而直接写副本不安全。--no-check-replica 是绕过这个检查,不是修复这个拓扑错误。

--replicate 且不带 --sync-to-source 时,命令行只接受一个源 DSN,工具自动发现该源的所有副本并逐个修。这是“一次修全部副本”的唯一方式(--sync-to-source 一次只能指定一个副本)。上线前可以用 --explain-hosts 看工具如何解释这些 DSN。

另外,--sync-to-source 和 --replicate 都要求 statement-based replication,工具会在自己的会话里设置 binlog_format=STATEMENT,执行用户需要 SUPER 权限。

三、--sync-to-source:只接受一个副本 DSN

pt-table-sync --execute --sync-to-source replica1

命令行上只能有这一个 DSN,且它是副本。工具自动找到它的源,在源上执行修改,靠复制流把变更带回副本。这是把副本拉回与源一致的常规安全路径——副本上的数据通常正是问题所在,直接改副本等于把问题又写回去一遍。

副作用必须提前说清楚:同一源上挂着的其它副本,同样会通过复制收到这批变更。理论上这些变更对它们是把值设成当前值的 no-op,但前提是拓扑干净、没有额外的复制过滤或触发器。这一点需在预发验证。

四、无主键 / 唯一键:改源不安全

REPLACE 只有在表上有唯一索引时才成立。没有唯一索引时,REPLACE 退化为普通 INSERT,改源会把重复行顺着复制流发给所有副本。

这类表没有别的选择,只能在副本上改,所以必须显式加上 --no-check-replica 表示知情:

pt-table-sync --execute --no-check-replica --sync-to-source replica1

source-source 下的无唯一键表更麻烦:改动必须写在目的端,此时必须加 --no-bin-log,否则改动会通过反向复制流回另一端,把另一侧的数据一起改掉。

文档的建议是:无主键 / 唯一键的表,最好换一种方式同步数据。

五、source-source:正确写法与错误写法的区别

已知 source2 上的 db.tbl 有问题:

pt-table-sync --execute --sync-to-source h=source2,D=db,t=tbl

含义是把 source2 当作副本,连到它的源 source1,在 source1 上改,改动经复制流回到 source2。

下面这条不要用:

# source-source 下不要这样写
pt-table-sync --execute h=source1,D=db,t=tbl source2

它直接在 source2 上改,改动会顺着复制流向 source1,把 source1 的数据冲掉。

六、唯一键冲突:UPDATE 被自动改写成 DELETE + REPLACE

假设表上 a 是主键、b 上有唯一索引:

-- 源           副本
-- a  b         a  b
-- 1  2         1  1
-- 2  1         2  2

这种数据用 UPDATE 无论怎么改都会撞唯一键。工具在第一次索引冲突之后会自动把语句改写成 DELETE + REPLACE,不需要人工干预。

代价是 binlog 里会变成两条语句而不是一条。下游如果有基于 binlog 的审计、增量同步或触发器链路,需要按两条来对待。这一点需在预发验证。

七、外键级联与 chunk 控制

表上带 ON DELETE / ON UPDATE 外键时,一次删除或更新可能级联改动子表,而子表并不在你的同步范围内,数据就被顺带改了。用 --check-child-tables 让工具在同步前拦截。

大表上如果 chunk 相关列没有索引,行选择会退化。用 --chunk-index 指定索引,用 --chunk-size 控制每个 chunk 的行数:

pt-table-sync --execute --replicate percona.checksum \
  --check-child-tables \
  --chunk-index=PRIMARY \
  --chunk-size=1000 \
  h=source1

超大 chunk 或 MyISAM 表还要考虑 --no-transaction:默认每个 chunk 包在事务里,MyISAM 下事务没有意义。

八、退出码 2 表示“发现并修复了差异”,不是失败

  • 0:无差异
  • 2:发现差异(带 --execute 时已修复)
  • 其它值:错误

脚本里必须把 2 当成功分支处理。否则每次真正修完东西都会触发告警,最后所有人都去忽略这个告警——等到真出错时也没人看。

--verbose 会按表打一行结果,包含 DELETE / REPLACE / INSERT / UPDATE 条数、算法、起止时间、退出码,可以拿来核对上面的判断。

九、场景对照表

场景是否安全正确命令
只预览,不写库安全pt-table-sync --dry-run --print --sync-to-source replica1
有 checksum 结果,修该源的全部副本安全pt-table-sync --execute --replicate percona.checksum h=source1
有 checksum 结果,只修一个副本安全pt-table-sync --execute --replicate percona.checksum --sync-to-source replica1
两个独立实例之间搬数据安全(目的地必须独立拓扑)pt-table-sync --execute h=host1,D=db,t=tbl h=host2
目的地是副本不安全,工具直接退出改用 --sync-to-source
无主键 / 唯一键的表只能改副本pt-table-sync --execute --no-check-replica --sync-to-source replica1
source-source 下的无唯一键表必须加 --no-bin-logpt-table-sync --execute --no-bin-log h=...,D=db,t=tbl h=...
source-source,已知 source2 数据有问题安全pt-table-sync --execute --sync-to-source h=source2,D=db,t=tbl
source-source 写成 h=source1,... source2不安全,会冲掉 source1 数据不要使用

执行顺序归纳成一条线:先 --dry-run --print 看语句,再对一个副本小范围 --execute,确认 binlog 形态与子表影响,最后才用 --replicate 批量过全部副本。有外键先加 --check-child-tables,无唯一键先确认自己接受“只改副本”这个前提。

推荐文章

程序员茄子在线接单