主主复制必须配置server-id、auto_increment_offset和log_slave_updates三者成对错开,否则必然主键冲突或同步中断:server a设server-id=1、offset=1、increment=2,生成奇数id;server b设server-id=2、offset=2、increment=2,生成偶数id;且两端均需启用log_slave_updates=1,确保双向binlog传播。

不能直接用默认配置搭主主复制,server-id、auto_increment_offset、log_slave_updates 这三项不配对,复制必然中断或主键冲突。
为什么 server-id 和自增参数必须成对错开
两台 MySQL 实例若都用 auto_increment_increment = 1,又没设 offset,插入新记录时会生成相同主键,造成同步失败(错误如 ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY')。server-id 不唯一则复制线程无法区分来源,log_slave_updates 关闭会导致从库收到的变更不写入自身 binlog,另一端就收不到——双向链路直接断掉。
必须这样配:
- Server A:
server-id = 1,auto_increment_offset = 1,auto_increment_increment = 2 - Server B:
server-id = 2,auto_increment_offset = 2,auto_increment_increment = 2
这样 A 生成 ID:1, 3, 5…,B 生成 ID:2, 4, 6…,物理上避开冲突。
log_slave_updates 是双向同步的开关
它控制“从库应用的事件是否记入自己的 binlog”。主主架构里,A 是 B 的主库,B 同时也是 A 的主库——所以 B 必须把从 A 拉来的变更再写进自己的 binlog,否则 A 就无法作为从库去拉 B 的更新。漏掉这行,SHOW SLAVE STATUS 里 Seconds_Behind_Master 可能为 0,但实际数据早已不同步。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
确认方式:
- 登录任一节点执行
SELECT @@log_slave_updates;,返回 1 才有效 - 配置文件中必须显式写
log_slave_updates = 1,MySQL 8.0 默认关闭,5.7 默认关闭 - 改完要重启 mysqld,仅
SET GLOBAL不生效
GTID 模式下 change master to 必须带 master_auto_position = 1
启用 GTID(gtid_mode = ON)后,不能再靠 MASTER_LOG_FILE 和 MASTER_LOG_POS 定位,否则会报错 ERROR 1236 (HY000): Got fatal error 1236 from master。必须用 GTID 自动定位:
CHANGE MASTER TO MASTER_HOST='192.168.4.52', MASTER_USER='repluser', MASTER_PASSWORD='Abc-1234', MASTER_AUTO_POSITION = 1;
注意点:
- 两台都要开
enforce_gtid_consistency = TRUE,否则建表含非确定性函数(如UUID())会拒绝执行 -
RESET MASTER会清空 GTID_EXECUTED,主主环境下严禁在已运行节点执行 - 首次配置建议用
mysqldump --set-gtid-purged=ON导出,否则导入后 GTID 不连续
检查 SHOW SLAVE STATUS 时重点盯哪几项
不是只看 Slave_IO_Running 和 Slave_SQL_Running 都是 Yes 就完事。真正容易被忽略的是:
-
Seconds_Behind_Master:长期 > 0 表示延迟,但值为 0 不代表实时——可能卡在某个事务里 -
Exec_Master_Log_Pos和Read_Master_Log_Pos差距大,说明 IO 线程拉得快、SQL 线程执行慢 -
Last_IO_Errno/Last_SQL_Errno为 0 才安全;非 0 时要看Last_IO_Error具体内容(比如网络超时、权限拒绝、表不存在) -
Retrieved_Gtid_Set和Executed_Gtid_Set应完全一致,否则有 GTID 跳过或执行失败
主主最脆弱的地方不在配置阶段,而在上线后——应用层若没做写请求路由隔离,两个节点同时 INSERT 同一张表的同一业务逻辑,即使 ID 不冲突,UPDATE 或 DELETE 也可能因执行顺序不一致导致最终状态错乱。这点没法靠数据库配置解决,得靠应用兜底。










