必须成对设置auto_increment_increment和auto_increment_offset,仅设offset无效;双主需统一increment=2、A设offset=1(生成奇数)、B设offset=2(生成偶数),且须写入my.cnf并重启mysqld生效。

auto_increment_increment 和 auto_increment_offset 必须成对设置
只改 auto_increment_offset 没用,MySQL 启动时用它定第一个自增值,但后续仍按默认步长 +1 递增。如果两节点都设 auto_increment_offset = 1 却没设 auto_increment_increment = 2,结果都是生成 1、2、3……同步瞬间就触发 ERROR 1062 (23000): Duplicate entry '5' for key 'PRIMARY'。
正确做法是:
- 双节点统一设
auto_increment_increment = 2 - Node A 设
auto_increment_offset = 1→ 生成 1, 3, 5, 7… - Node B 设
auto_increment_offset = 2→ 生成 2, 4, 6, 8… - 配置必须写进
my.cnf并重启 MySQL 生效;SET GLOBAL只影响新连接,复制线程可能还在用旧值
server-id 和 log_slave_updates 是双向复制的前提
双主不是“互相当主库”这么简单。每个节点既要当 Master(生成 binlog),又要当 Slave(执行对方的 binlog),所以 log_slave_updates = ON 是硬性要求——否则对方的变更不会写入本地 binlog,另一端就收不到。
server-id 必须全局唯一且非 0 或 1(建议用 101、102 这类可读性强的值)。若两节点 server-id 相同,复制线程启动直接拒绝,START SLAVE 报错或静默失败。
其他必要参数还包括:
-
log-bin:开启 binlog,路径建议绝对路径如/var/log/mysql/mysql-bin.log -
gtid_mode = ON+enforce_gtid_consistency = ON:强制 GTID,避免位点错乱 - 忽略
binlog_ignore_db类配置:一旦漏掉业务库,该库变更不记 binlog,复制链路就断了
GTID 不能防冲突,只能让冲突更快暴露
很多人误以为开了 GTID 就能自动解决双主冲突,其实 GTID 只负责事务唯一标识和幂等重放,不参与冲突检测或仲裁。
典型场景:UPDATE users SET balance = balance + 100 WHERE user_id = 1001 在 A 和 B 上同时执行,两个事务各自成功、各自生成不同 source_uuid 的 GTID,复制过去后 SQL 线程照常执行——结果是后执行的那个覆盖前一个,不是合并,也不是报错。
也就是说:
-
auto_increment_offset+increment只防 ID 冲突,不防业务逻辑冲突 - 插入带唯一约束字段(如
email、order_no)依然会报ERROR 1062 - 删除+更新并发、同一行被两端反复修改,最终状态不可预测
- 真正规避手段只能是应用层写路由(比如一致性哈希)、禁用双向 UPDATE/DELETE、或强制 Active-Passive 模式
切换后必须手动校准 AUTO_INCREMENT 值
主从切换或故障恢复后,新主库的 AUTO_INCREMENT 值不会自动同步,它只基于本机 SELECT MAX(id) 初始化(MySQL 5.7 及之前),不看对方 binlog,也不管 GTID 集合。
常见现象是:A 宕机前已写到 ID=1005,B 升为主后 AUTO_INCREMENT 还是 1001,下一条 INSERT 就撞上 1005,直接报错。
修复步骤必须手动执行:
- 在目标节点上查所有相关表当前最大 ID:
SELECT MAX(id) FROM your_table; - 取所有节点中该表的最大值,+1 得到安全起点 N
- 执行:
ALTER TABLE your_table AUTO_INCREMENT = N; - 验证:
SHOW CREATE TABLE your_table;确认字段已更新 - 注意:mysqldump 导出时若用了
--skip-auto-increment或工具过滤了ALTER TABLE ... AUTO_INCREMENT=行,导入后也得补这一步
最易被忽略的是:这个操作不是“配完就一劳永逸”,每次角色变更、每次批量导入、每次跨库写入历史清理后,都要重新核对。ID 冲突从来不是配置问题,而是状态管理问题。


















