mysql 8.0 双向复制≠异地多活,需严格配置auto_increment_offset/offset、唯一server-id、log-slave-updates=on、强制gtid且一致性校验通过,否则写入丢失或主键冲突。

MySQL 8.0 的双向复制(Master-Master)本身不等于异地多活,它只是基础链路;真正能用的前提是:auto_increment_offset 和 auto_increment_increment 配对正确、server-id 全局唯一、log-slave-updates 开启、两端都强制启用 GTID 且一致性校验通过——漏掉任一环,写入就会“消失”或报 Duplicate entry '1' for key 'PRIMARY'。
为什么 CHANGE MASTER TO 后写入不生效?
最常见现象是:A 库 INSERT 成功,B 库查不到;或两边都插入但主键冲突。根本不是网络或权限问题,而是自增 ID 生成规则没隔离。
-
auto_increment_increment必须设为相同值(如2),auto_increment_offset必须错开(A 设1,B 设2),否则两个实例都会生成1,2,3... -
server-id不能硬编码为1(尤其 Docker 场景下 IP 变更后易撞车),必须全局唯一且非0 - 必须开启
log-slave-updates = ON,否则 B 收到 A 的 binlog 后不会记录到自己的 binlog 中,导致无法再转发给 A,双向链路实际是单向的
GTID 模式下复制通道建立失败的典型表现
SHOW SLAVE STATUS 中 Retrieved_Gtid_Set 为空,说明从库压根没拉到任何事件——不是数据没同步,是复制根本没跑起来。
- 检查两端是否都设了
gtid_mode = ON且enforce_gtid_consistency = ON,缺一不可 - 执行
CHANGE MASTER TO时必须带MASTER_AUTO_POSITION = 1,禁止混用MASTER_LOG_FILE+MASTER_LOG_POS - 若从库之前是传统模式,先执行
RESET SLAVE ALL清空旧状态,再重配,否则 GTID 位点会错乱 - 确认主库
SHOW MASTER STATUS输出的Executed_Gtid_Set非空;若为空,说明主库虽开了 GTID,但尚未执行过任何事务(DDL/DML)
应用层写入双主前必须规避的三类操作
MySQL 不解决跨节点并发更新冲突,所谓“双向同步”只保证语句/行事件被重放,不保证业务逻辑一致。
- 禁用无条件
UPDATE,例如UPDATE order SET status = 'paid'—— 两地同时执行,结果取决于谁后 apply,覆盖不可控 - 敏感业务(支付、库存扣减)必须路由到单一中心节点写入,异地仅允许读;多活 ≠ 所有表都双写
- 如需双写同一张表,每条
UPDATE必须带WHERE updated_at = ?时间戳校验,靠应用层重试+版本比对兜底
真正难的从来不是配置命令,而是厘清哪些表能双写、哪些字段必须加乐观锁、哪些业务必须降级为单中心写入——这些决策藏在业务逻辑里,不在 my.cnf 里。











