mysql双主架构本身不解决数据冲突,仅靠auto_increment_offset和auto_increment_increment只能避免insert主键重复,无法防范update/delete并发覆盖、业务逻辑冲突及应用层写同一行;必须同步配置innodb_autoinc_lock_mode=0、log_slave_updates=on、server-id唯一且replicate-same-server-id=0,并配合写入分离、幂等操作与逻辑删除等应用层策略才能保障一致性。

MySQL 双主架构本身不解决数据冲突,它只负责复制,冲突必须靠人为设计来规避。单纯调自增步长只能防 INSERT 主键重复,对 UPDATE、DELETE、业务逻辑覆盖完全无效。
自增 ID 冲突:必须配齐三组参数
仅设 auto_increment_offset 和 auto_increment_increment 不够,漏掉任一关键项都会在批量插入或延迟场景下翻车:
- 主库 A 设
auto_increment_increment = 2、auto_increment_offset = 1→ 生成 1/3/5… - 主库 B 设
auto_increment_increment = 2、auto_increment_offset = 2→ 生成 2/4/6… - 两台都必须设
innodb_autoinc_lock_mode = 0(传统锁模式),否则INSERT ... SELECT会跳号、错号 - 必须开启
log_slave_updates = ON,否则本机 binlog 不记录 relay 日志,双向复制断裂 -
server-id必须全局唯一(如 A=1、B=2),且需配置replicate-same-server-id = 0防回环复制
UPDATE/DELETE 冲突:根本没法靠 ID 规避
就算 ID 完全错开,以下操作仍会静默导致数据错误:
-
UPDATE users SET balance = balance + 100 WHERE id = 123:两端并发执行,最终值只保留一次加法结果 DELETE FROM logs WHERE created_at :跨时区或延迟下,两边删的行集可能不一致- 无 WHERE 的
UPDATE t SET status='done'或DELETE FROM t:复制延迟时极易误操作全表
真正可行的做法是:禁止应用直连双主做自动负载均衡写入;所有变更走幂等逻辑,例如带版本号或时间戳条件更新:UPDATE t SET val=?, version=version+1 WHERE id=? AND version=?;物理删除统一转为 UPDATE ... SET is_deleted=1。
写入控制策略比参数更重要
参数只是让复制不崩,而谁往哪写、什么时候写、怎么写,才决定数据是否一致:
- 按业务拆分:用户表全走 A,订单表全走 B
- 按数据特征路由:
user_id % 2 == 0写 A,否则写 B - 地域分流:国内流量写 A,海外写 B
- 主动-被动模式:日常只用 A 写,B 仅备灾;故障时切流,避免常态双写
冲突发生后别指望自动修复
一旦数据分叉,pt-table-sync 这类工具只能在完全无写入的窗口期临时校正,且默认按“目标库覆盖源库”执行,可能丢数据。更务实的做法是:
- 用
pt-table-checksum定期巡检,早发现偏差 - 关键表加
last_modified_time字段,结合 binlog 解析识别异常时间跳跃 - 监控
SHOW REPLICA STATUS\G中的SQL thread error和Seconds_Behind_Master异常波动
双主不是高可用银弹,运维成本高、风险面广。若非强需求(如跨机房双活容灾),建议优先选用 MySQL Group Replication、TiDB 或 MHA 等原生支持一致性保障的方案。











