主从延迟和数据不一致需分场景处理:强一致性读必须走主库;从库冲突须停sql线程、手动比对修复;mysqldump适合小表全量重建,pt-table-sync适合大表行级修复;覆盖前必停sql_thread并注意gtid一致性。

主从延迟导致 SELECT 读到旧数据,怎么办?
MySQL 主从复制不是实时的,Seconds_Behind_Master 非零时,应用从从库查数据就可能拿到过期结果。这不是 bug,是架构取舍。
- 应用层要区分「强一致性读」和「最终一致性读」:关键路径(如支付后查订单状态)必须走主库,用
SELECT ... FOR UPDATE或显式指定master连接池 - 从库读场景加简单延迟判断:执行
SELECT MASTER_POS_WAIT(...)等待指定 binlog 位点,但只适合低频、可阻塞的操作 - 不要用
SLEEP(1)或重试次数硬编码——网络抖动或大事务会让延迟忽高忽低,毫无可靠性
Duplicate entry 冲突:从库写入被主库同步覆盖了
主从架构下,从库绝对不能写。但有些运维误操作、脚本残留或中间件路由错误,会导致从库出现 INSERT 或 UPDATE,后续主库同主键数据同步过来,直接报 Duplicate entry 'xxx' for key 'PRIMARY',复制中断。
- 立即查
SHOW SLAVE STATUS\G,确认Seconds_Behind_Master是否为NULL,SQL_Remaining_Delay和Slave_SQL_Running_State看卡在哪条语句 - 切勿直接
SET GLOBAL sql_slave_skip_counter = 1跳过——跳过的不只是冲突行,还可能跳过依赖它的后续变更 - 正确做法是:停掉 SQL 线程 → 导出冲突表当前从库数据 → 对比主库该表的
SELECT ... INTO OUTFILE结果 → 手动合并差异(保留主库值,或按业务规则取舍)→ 用LOAD DATA INFILE或INSERT ... ON DUPLICATE KEY UPDATE修复 → 再启同步
手动同步表数据时,mysqldump 和 pt-table-sync 怎么选?
两者目标一样,但行为逻辑完全不同。
-
mysqldump是全量重建:锁表、导出、清空、导入。适用于小表(--single-transaction 减少主库锁,但无法规避从库复制延迟带来的快照不一致 -
pt-table-sync是行级比对修复:连主从两端,逐行校验 checksum,只同步差异行。适合大表、在线修复。但要求主从表结构完全一致、有主键或唯一索引,且从库不能有未提交的本地写入 - 二者都绕不开 binlog 格式限制:
STATEMENT模式下,NOW()、UUID()等函数在主从可能生成不同值,导致 checksum 不匹配,误判为数据不一致
覆盖从库数据前,为什么必须先停 SQL_THREAD?
从库复制由两个线程协作:IO_THREAD 拉日志,SQL_THREAD 执行日志。手动同步/覆盖时如果只停 IO_THREAD,SQL_THREAD 仍在跑,可能把刚覆盖的新数据又按旧 binlog 回滚掉。
- 停同步必须执行
STOP SLAVE SQL_THREAD(不是STOP SLAVE),保留 IO 线程拉日志,避免主库新事件堆积太多 - 覆盖完成后,用
START SLAVE SQL_THREAD恢复,而不是全启;等Seconds_Behind_Master归零再观察 30 秒 - 最容易被忽略的是 GTID 模式下的
gtid_executed:手动写入会改变该变量值,导致后续同步找不到起点。此时需用SET GTID_NEXT='xxx'; BEGIN; COMMIT;补齐缺失的 GTID,否则START SLAVE直接失败
主从数据修复从来不是“覆盖就完事”,真正麻烦的是覆盖之后那几秒——binlog 位点错位、GTID 链断裂、checksum 校验器误判,每个都可能让问题延后爆发。










