如何解决主键冲突导致的复制中断_Slave_skip_errors配置与风险

2次阅读

应优先用 stop replica skip counter = 1(mysql 8.0.26+),rbr模式下需设 slave_exec_mode = ‘idempotent’;跳过仅治标,须查清主键冲突根源并校验数据一致性。

如何解决主键冲突导致的复制中断_Slave_skip_errors配置与风险

主键冲突让复制停在 Error 1062,怎么跳过?

直接跳过不是不行,但 Slave_skip_errors 是个全局开关,一旦启用,所有错误类型都可能被忽略,包括真正要命的 ERROR 1032(行不存在)或 ERROR 1053(服务器关闭),不是只管主键冲突。它不区分语句来源、不校验数据一致性,跳过之后从库数据就和主库对不上了。

实操建议:

  • Slave_skip_errors 只应在紧急恢复时临时用,用完立刻关掉,不能写进配置文件长期开启
  • 跳过前先查 SHOW SLAVE STATUSG,确认 Last_SQL_Error 确实是 Duplicate entry 'xxx' for key 'PRIMARY'
  • 跳过命令是 SET GLOBAL sql_slave_skip_counter = 1;,不是改配置再重启——后者要重启 IO/SQL 线程,容易丢事件
  • MySQL 8.0.26+ 支持 STOP REPLICA SKIP COUNTER = 1;,更安全,推荐优先用

为什么 sql_slave_skip_counter 有时不生效?

因为它只对基于语句复制(SBR)有效,而 MySQL 5.7.7+ 默认用的是基于行复制(RBR)。在 RBR 下,sql_slave_skip_counter 被忽略,跳不过去。

实操建议:

  • 先看 SHOW SLAVE STATUSG 里的 Replicate_Rewrite_DBExec_Master_Log_Pos,再结合 select @@binlog_format; 确认复制格式
  • RBR 场景下,必须用 SET GLOBAL slave_exec_mode = 'IDEMPOTENT';,它允许重复插入时忽略主键冲突(仅限 INSERT 类操作)
  • IDEMPOTENT 模式有副作用:它也会让 UPDATE 找不到行时不报错,相当于静默失败,监控上容易漏掉
  • 别混淆 slave_exec_modesql_slave_skip_counter——前者是行为模式,后者是计数器,机制完全不同

想精准跳过某条冲突 SQL,而不是整个事件?

不能。MySQL 复制的最小执行单位是「事件(Event)」,不是单条 SQL。一个 INSERT ... SELECT 或批量 INSERT 会被打包成一个事件,sql_slave_skip_counter = 1 跳过的是一整个事件,里面可能含多条语句。

实操建议:

  • 如果主库误执行了不该有的 INSERT,最稳妥的方式是:在从库手动 delete 冲突行,再 START SLAVE;
  • mysqlbinlog 解析主库 binlog,定位到出问题的 event 位置(at xxx),然后用 CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='xxx', SOURCE_LOG_POS=yyy; 跳到下一条
  • 注意:SOURCE_LOG_POS 必须指向下一个 event 的开头,不是当前 event 的末尾,算错会导致复制错位或重复执行
  • position 是高危操作,务必先在测试库验证 binlog 解析结果

pt-slave-restart 自动跳过靠谱吗?

它只是封装sql_slave_skip_counter 和状态轮询,能自动检测并跳过指定错误码(比如 --error-numbers=1062),但没解决根本问题:跳过之后数据不一致依然存在。

实操建议:

  • 适合临时救急,比如半夜报警、只差几条数据且业务可接受短暂不一致
  • 它默认每秒检查一次复制状态,频繁跳过会掩盖真实问题,比如主从写入逻辑不同步、应用双写未关等
  • 不要用它替代数据校验,跳过之后必须跑 pt-table-checksum 对比主从表级一致性
  • 它对 GTID 复制支持有限,开启 GTID 后需配合 --recursion-method=none 和手动 SET GTID_NEXT,复杂度陡增

真正难的不是跳过,而是确认这条冲突数据本就不该存在——是主库误操作?从库残留脏数据?还是应用层没做幂等?这些不会因为跳过就消失。

text=ZqhQzanResources