MySQL主从复制中,从库的SQL线程在回放主库binlog事件时,如果试图插入一条主键或唯一索引已存在的记录,就会抛出1062错误(Duplicate entry),导致复制线程停止。这种情况在从库被误写入、主从切换后数据未对齐、或早期版本并行复制乱序回放时都可能出现。处理该报错的核心不是简单让线程跑起来,而是在保证数据一致性的前提下恢复同步。

一、1062错误的底层原理
MySQL复制分为三个线程:主库binlog dump、从库IO线程和SQL线程。IO线程负责拉取binlog并写入relay log,SQL线程读取relay log并重放。当重放INSERT语句时,存储引擎做唯一性约束检查,若发现冲突便返回ER_DUP_ENTRY(错误码1062),SQL线程随之报错退出,复制状态变为Slave_SQL_Running: No。
在基于文件位置的复制中,错误会停留在某个binlog文件和位置;在GTID模式下,则会标记某个事务执行失败。理解这一点很重要,因为跳过方式取决于复制模式。如果冲突行在从库是多余数据,跳过可行;若从库缺失该行而其他表依赖它,盲目跳过会造成后续隐式不一致。
二、传统位置复制下跳过错误点位
对于未开启GTID的实例,常用手段是设置sql_slave_skip_counter跳过若干事件。注意该变量跳过的是“事件数”而非“事务数”,对包含多事件的事务要谨慎。典型步骤如下:
-- 停止从库SQL线程 STOP SLAVE SQL_THREAD; -- 跳过1个事件(若报错事务仅1个事件) SET GLOBAL sql_slave_skip_counter = 1; -- 启动SQL线程 START SLAVE SQL_THREAD; -- 查看状态确认无报错 SHOW SLAVE STATUSG
这种方法的优点是简单直接,不需要重启实例。缺点也很明显:它是盲跳,不会校验数据内容。如果在生产环境频繁使用,复制链路可能逐渐偏离主库。因此建议先通过SHOW SLAVE STATUS拿到报错时的Master_Log_File与Exec_Master_Log_Pos,用mysqlbinlog解析该位置附近的事件,确认冲突SQL与涉及的主键。
例如可在一台临时实例上重放相关binlog片段,对比主从对应行的差异。若从库该行是脏数据,删除后再启动复制比跳过更安全。以下为解析relay log的示例:
mysqlbinlog --verbose --base64-output=DECODE-ROWS /var/lib/mysql/relay-bin.000123 --start-position=154 | grep -A 20 "INSERT"
三、GTID模式下的空事务跳过法
当复制采用GTID后,sql_slave_skip_counter被禁用,必须改用注入空事务的方式。思路是:让从库“假装”已执行那个报错的GTID,从而跳过它。操作前需从Retrieved_Gtid_Set与Executed_Gtid_Set差异中定位失败事务。
-- 查看从库状态,找到报错GTID SHOW SLAVE STATUSG -- 在从库注入空事务替代原事务 STOP SLAVE; SET GTID_NEXT='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:12345'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; START SLAVE;
空事务方法比盲跳更可控,因为它精确指定了要跳过的事务ID。但依然要确认该事务确实仅造成重复键且不影响业务语义。如果主库那条INSERT本应生效,从库却因已有数据跳过,那么从库少了一行“新数据”的变更轨迹,虽然行内容相同,但像自增ID消耗、触发表等副作用可能不同。
在GTID环境中还可利用slave_skip_errors静态参数跳过指定错误码,但不推荐长期开启,因为这会让所有1062都被静默忽略。临时排障可以接受,常态化则是隐患。
四、优先修复数据而非跳过
多数1062源于从库被直接修改。更稳妥的流程是:先用pt-table-checksum核对主从差异,再用pt-table-sync修复。以下为校验命令示例:
pt-table-checksum --replicate=test.checksums --databases=app_db h=127.0.0.1,u=root,p=pass
若差异仅集中在冲突表,可导出主库对应行并在从库上用REPLACE或先DELETE后INSERT对齐,再重启复制。这样避免了跳过带来的逻辑空洞。只有确认冲突无害且业务允许短暂不一致时,才使用前述跳过手段。
此外,建议为从库账号收回写权限,统一通过只读中间件访问,从源头减少人为写入导致的1062。监控上可将Slave_SQL_Running与Last_SQL_Errno接入告警,使报错在秒级被发现。
五、方法对比与选择建议
下表总结两种主要跳过方式的特征:
| 复制模式 | 跳过手段 | 精确度 | 风险 |
|---|---|---|---|
| 非GTID | sql_slave_skip_counter | 按事件数,较粗 | 易跳多或跳错事务 |
| GTID | 空事务注入 | 按事务ID,精确 | 遗漏事务业务含义 |
实际处理时,先把复制停在读档点,保留现场;再解析binlog明确冲突SQL;最后依据数据重要性决定修复或跳过。遵循“能修不跳、能精跳不盲跳”的原则,MySQL复制的1062报错就不会成为棘手故障。