生产环境不建议默认启用mysql双主+keepalived双写,必须满足同步稳定、vip切换可靠、故障恢复无冲突三点;需强制启用gtid+row复制、错开自增id、log-slave-updates=1,并用sql级检测脚本替代端口检测,同时严格时间同步。

生产环境里直接上 MySQL 双主 + Keepalived 是高风险操作,不建议默认启用双写。真正可用的配置必须满足:MySQL 同步稳定、VIP 切换无脑可靠、故障恢复不引发数据冲突——这三点缺一不可。
MySQL 双主同步必须用 GTID + ROW 格式
基于 binlog 位置的传统复制在双主场景下极易断链,GTID 是唯一能保证事务可追溯、切换后自动续同步的机制。ROW 格式则避免了 STATEMENT 模式下函数/时间类语句导致的从库执行偏差。
-
gtid_mode=ON和enforce_gtid_consistency=ON必须同时开启,否则CHANGE MASTER TO无法使用AUTO_POSITION -
binlog-format=ROW是硬性要求,MIXED或STATEMENT在双主中会因非确定性语句造成主键冲突或数据不一致 -
log-slave-updates=1必须启用,否则 A 节点同步来的数据不会写入自己的 binlog,B 节点就收不到二次转发 - 自增字段要错开:
auto_increment_offset=1(A 节点)、auto_increment_offset=2(B 节点),auto_increment_increment=2两边保持一致
Keepalived 的检测脚本不能只查端口
只用 tcp_check 检 3306 端口是典型误判:MySQL 进程活着但复制已断、SQL 线程卡死、甚至 slave_sql_running=No,端口照样通。这种“假活”状态会导致 VIP 没有及时漂移,业务持续写入一个不同步的节点。
- 检测脚本必须连接本地 MySQL,执行
SHOW SLAVE STATUS\G并检查Slave_IO_Running和Slave_SQL_Running是否均为Yes - 还要验证
Seconds_Behind_Master是否在合理阈值内(例如 ≤ 30 秒),超时即视为异常 - Keepalived 配置中需用
vrrp_script定义该脚本,并在track_script中绑定到实例,权重变化触发切换 - 不要设
non_preemptive(非抢占),否则故障恢复后 VIP 不会自动回切,人工干预增加运维负担
应用连接方式决定是否真高可用
VIP 本身不解决应用层问题。如果应用直连 VIP 且没做连接池重连或读写分离逻辑,单点故障确实能切,但连接中断期间的事务丢失、连接池未清理、DNS 缓存未刷新等问题会暴露出来。
- 应用必须配置连接超时(
connect_timeout)、等待超时(wait_timeout)和自动重连(如 JDBC 的autoReconnect=true) - 禁止应用在两个 MySQL 实例上并发写同一张表;若需双活写,必须按业务域拆分表或库,确保写入隔离
- 测试阶段务必模拟 kill -9 mysqld 进程,观察 VIP 漂移耗时(正常应 ≤ 3 秒)、应用重连成功率、是否有连接残留或事务回滚失败
- 线上首次部署前,先关掉一台 MySQL 的
slave线程,验证检测脚本能正确触发 VIP 切换
最易被忽略的一点:两台服务器的系统时间必须严格同步。NTP 偏差超过 1 秒,GTID 复制可能拒绝同步,show slave status 会报 Retrieved_Gtid_Set 与 Executed_Gtid_Set 不匹配——这不是配置错误,是时间不同步导致的 GTID 事务排序混乱。











