双主架构必须从设计上杜绝应用层并发双写,仅靠配置无法防止冲突;auto_increment_offset与increment须配对错开(如A设1/2、B设2/2)以避免主键冲突;binlog_format必须为ROW;GTID加半同步是故障切换可信基础;VIP切换需配合健康检测防脑裂。

双主架构不能靠“防双写”来保安全,必须从设计上杜绝应用层并发双写——配置再严,也拦不住两个业务进程同时往两台库INSERT同一张表。
auto_increment_offset 和 auto_increment_increment 必须配对错开
这是避免自增主键冲突的底线配置。两台节点不能都用默认的 auto_increment_increment=1,否则只要两边同时 INSERT,必然撞主键。
- 节点 A:设
auto_increment_offset=1,auto_increment_increment=2→ 生成 1,3,5,7… - 节点 B:设
auto_increment_offset=2,auto_increment_increment=2→ 生成 2,4,6,8… - 这两个参数必须在
my.cnf中静态配置,且重启生效;运行时改只对新连接生效,已有连接可能仍用旧值 - 注意:该机制只保护
INT自增列,不保护 UUID、雪花 ID 或应用层生成的主键
binlog_format=row 是双主环境的强制项
用 STATEMENT 格式在双主下极易引发数据不一致:比如 UPDATE t SET c=NOW() 在两边执行时间不同,结果就不同;MIXED 会自动降级,但降级逻辑不可控。
- 必须显式设
binlog_format=row,并在所有节点上验证:SELECT @@binlog_format; -
ROW模式能精确记录每一行变更,冲突发生时至少能定位到哪条记录被覆盖,而不是猜“为什么值变了” - 副作用是 binlog 体积变大、网络传输压力略升,但相比数据错乱,这是可接受代价
GTID + 半同步复制不是锦上添花,而是故障切换的可信基础
没有 GTID,CHANGE MASTER TO 手动指定 binlog 文件和 position 极易出错;没有半同步,主库提交成功就返回客户端,但备库可能根本没收到日志,切换后直接丢数据。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 启用前确认所有节点已开启:
gtid_mode=ON、enforce_gtid_consistency=ON - 半同步插件需分别在主从端安装:
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'(主)和INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'(从) - 关键参数要调:
rpl_semi_sync_master_timeout=10000(超时 10 秒降级为异步,避免阻塞业务),且必须检查状态:SHOW STATUS LIKE 'Rpl_semi_sync%';
真正的“数据对冲”不在数据库配置里,而在 VIP 切换逻辑中
所谓“对冲”,本质是防止脑裂:当网络分区发生,两台节点都以为对方挂了,各自升为主并接受写入,恢复后变成两套不一致的数据——这时任何复制配置都救不回来。
- KeepAlived 必须配合 MySQL 健康检测脚本,不能只 ping 端口;脚本要查
SELECT @@read_only;和SHOW SLAVE STATUS\G的Seconds_Behind_Master是否为 0 - VIP 漂移后,原主库恢复时必须自动设为
read_only=1,并停止 SQL 线程,等人工确认无脑裂再手动重置复制关系 - 不要依赖 MMM 这类老工具自动切 writer:它不校验数据一致性,只看复制线程是否 running,容易把延迟严重的节点误判为健康
最常被忽略的一点:双主不是为了双写,而是为了单写+秒级切换。所有试图让应用“智能路由写请求到不同库”的方案,在真实业务流量下都会暴露主键冲突、更新丢失、事务隔离异常等问题——除非你已把数据按库/表彻底分片,且写入路径完全隔离。










