bigywater.tech
MySQL / InnoDB · 96

GTID 自动定位

真实往replica注入一个空GTID事务,再让source自然产生同一个GTID号的真实数据,看自动定位机制会不会静默丢数据。

永久缺1行
GTID号冲突导致的真实数据分叉
0个错误报告
两边SQL线程真实都显示健康

做的事:真实往replica注入一个"空事务",抢占一个未来的GTID号

代码(在replica上)STOP REPLICA; SET GTID_NEXT='ea38af54-...:418'; BEGIN; COMMIT; -- 真实一个空事务,只是为了标记这个GTID"已执行" SET GTID_NEXT='AUTOMATIC';

验证:source真实自然生成了同一个GTID号的真实数据

代码(在source上)INSERT INTO shop.orders (item, qty) VALUES ('elderberry', 1); -- source自动分配的GTID号,真实凑巧也是:418(因为这是source上的第418个事务)
实测 · 本机重启复制之后的真实数据对比
source真实查询:   1 apple 2 banana 3 cherry 4 date 5 elderberry   (5行)
replica真实查询:  1 apple 2 banana 3 cherry 4 date                (4行,永久卡住!)

验证:两边SQL线程都真实显示健康,没有任何报错

实测 · 本机SHOW REPLICA STATUS真实输出
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Last_Error: (空)
这是GTID自动定位机制真实一个容易被忽视的风险:SOURCE_AUTO_POSITION=1让replica只根据GTID号判断"这个事务我是不是已经执行过",如果某个GTID号真实已经被标记成执行过(不管是真的执行过,还是像本文这样手动注入了一个空事务),之后source上带着同一个GTID号的任何真实数据变更,都会被replica真实静默跳过,不会报错、不会告警——数据真实永久性地悄悄分叉了。本文这个场景是刻意构造出来验证机制的边界,真实生产环境里更常见的触发路径是:DBA为了跳过一个真实报错的坏事务,手动注入了一个空GTID,如果这个GTID号真实之后又被source的一次RESET MASTER或者故障切换重新分配给了一个不同的真实事务,就会真实踩中这个坑。真实的教训是:手动注入空GTID是一个需要谨慎对待的应急操作,事后要真实确认对应的GTID号不会再被复用。

分步演示:一次真实的GTID冲突,从注入到数据分叉

每一步都是本文上面用真实两节点复制环境跑出来的原始结果。

GTID号被复用,数据真实悄悄分叉了
这一步新验证的场景

    本文用到的工具

    • 本机真实的两节点复制实验环境,手动注入空GTID事务 + source真实新增数据对比
    • SET GTID_NEXT + SOURCE_AUTO_POSITION=1
    京ICP备2026067502号-1京公网安备11010502063487号