双主复制需配置互补的auto_increment_offset和increment避免主键冲突;读写分离须依赖ProxySQL等代理层而非直连;Keepalived VIP应绑定HAProxy而非MySQL节点;故障切换后须人工核对GTID或binlog位点再恢复复制。

双主复制必须解决自增ID冲突
MySQL双主不是简单配两个server-id就完事。最常踩的坑是写入时主键冲突,现象是Duplicate entry 'X' for key 'PRIMARY'。这是因为两个节点默认都从1开始自增,一并发插入就撞车。
必须在两台机器的my.cnf里配一组互补的步长和偏移:
-
auto_increment_increment = 2(步长为2) - 节点A设
auto_increment_offset = 1→ 生成1,3,5… - 节点B设
auto_increment_offset = 2→ 生成2,4,6…
这个组合能保证主键不重,但代价是ID稀疏。如果业务依赖连续ID(比如订单号展示),就得额外处理,不能直接用AUTO_INCREMENT字段做业务标识。
读写分离不能只靠双主,必须加代理层
双主本身只解决“写可分摊”,不解决“读怎么分发”。应用直连两个主库做负载均衡,会立刻暴露一致性问题:因为复制有延迟,刚写入A库的数据,立刻从B库读可能读不到。
所以必须引入中间件,常见选型有三个:
-
ProxySQL:规则灵活,支持^select.*for update这种精确匹配,适合复杂SQL场景 -
HAProxy:L4层转发,轻量,但只能按连接分发,无法识别SQL类型,读写分离要靠应用层约定端口 -
MySQL Router:官方出品,对InnoDB Cluster友好,但对传统双主支持弱,需手动配置路由组
别用DNS轮询或客户端随机选库——没有健康检查,挂了都不知道。
Keepalived VIP不能直接绑在双主上
很多教程让Keepalived把VIP漂移到MySQL节点,这是危险操作。一旦VIP切到B节点,所有读写请求全打过去,但B节点的复制线程可能卡在IO或SQL线程,数据已滞后,业务立刻读到旧数据甚至报错。
正确做法是把Keepalived和HAProxy部署在同一层,VIP绑定在HAProxy节点上,再由HAProxy探活后端MySQL节点。配置关键点:
-
option mysql-check user haproxy_check:用专用账号探测MySQL是否真正可服务 -
balance leastconn:避免某节点因慢查询堆积连接 - 后端
mysql_servers的weight别设一样,主库权重应高于从库(比如1000 vs 500)
双主故障切换后,必须人工确认GTID或binlog位置
当一台主库宕机、流量切到另一台后,恢复原节点时不能直接启动复制。因为双主复制链路中断期间,存活节点可能已写入新事务,而宕机节点的日志位点已落后。强行拉起复制,大概率触发Slave_SQL_Running: No且Last_SQL_Errno: 1062。
恢复前必须做三件事:
- 查存活节点当前
SHOW MASTER STATUS的File和Position - 查宕机节点
SHOW SLAVE STATUS\G里的Relay_Master_Log_File和Exec_Master_Log_Pos - 对比两者是否一致;不一致就得用
CHANGE MASTER TO ... MASTER_LOG_FILE='xxx', MASTER_LOG_POS=yyy手工对齐
这步没法全自动,脚本也容易误判。线上环境建议每次切换后,先人工核对一次复制状态,再放行写流量。


















