记录一下那天晚上的排查过程。MySQL 5.7 的主从复制中断,show slave status 里 Slave_SQL_Running 是 No,Last_Error 写 1062 Duplicate entry 12345 for key PRIMARY,业务侧读到的数据停在几小时前。

刚开始盯着「row 格式下 insert 与 delete 的顺序被打乱,中间态被写进从库」,折腾了半个多小时,排掉了。

原因不止一个,得分开看。主库上做过手工补数据,从库已经存在同一主键,重放时直接冲突。还有一种是从库被写过,binlog 重放时撞上本地已有的行。

不容易想到的是,gtid_mode 打开后事务跳过的判断失效,重复事务没有被忽略。

上来先看停在哪条语句、哪个 GTID

mysql -e "show slave status\G" | grep -E 'Last_Error|Exec_Master_Log_Pos|Retrieved_Gtid'

随后核对两端的这行数据是否一致

mysql -e "select * from db1.orders where id=12345"

接着把从库这行按主库内容修正

mysql -e "replace into db1.orders select * from db1.orders where id=12345"

跳过当前事务并恢复复制

mysql -e "set global sql_slave_skip_counter=1; start slave;"

别只看报错消失,验证要多做一步。show slave status 里两个线程都是 Yes,Seconds_Behind_Master 逐步回落到 0,Last_Error 变成空。

提醒一点。跳过一个事务只是止损,跳过的数据必须手工补齐;根治要让从库只读,并禁止在主库上手工改数据后不同步到从库。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189