MHA 仅是故障切换工具,非高可用集群;实现自动切换需搭配 VIP、脚本及外部健康检查,否则主库失联。

MHA 本身不提供高可用集群,它只是故障切换工具;想靠它实现“自动切换集群”,必须搭配 VIP、脚本和外部健康检查,否则切完主库就失联。
为什么 MHA 的 master_ip_failover 脚本常失效
多数人直接抄网上的 Perl 脚本,但漏掉三个硬性前提:
-
ssh必须免密通到所有节点(包括自己),且mysql用户能执行ip命令(常见于 CentOS 7+ 默认没给 mysql 用户网络权限) -
master_ip_failover只在切换时触发一次,不会持续探测 VIP 是否存活——如果新主库上 VIP 被手动清掉或网卡 down,MHA 不会重挂 - 脚本里写的
ifconfig在较新系统已被废弃,得换成ip addr,否则静默失败
建议用这个最小可用片段验证(替换 eth0 和 192.168.1.100):
# 在 new master 上执行 ip addr add 192.168.1.100/24 dev eth0 label eth0:1 # 切换后立刻 ping 测试,别只看 MHA 日志里的 "OK"
MySQL 主从状态必须满足 Seconds_Behind_Master == 0 才能切
MHA 默认拒绝在从库延迟时切换,这是对的,但容易被误判:
- 监控项
Seconds_Behind_Master是整数,当值为NULL(IO 线程断)或负数(GTID 模式下偶尔出现)时,MHA 直接报错退出,不走任何 fallback 逻辑 -
repl_password必须和CHANGE MASTER TO里用的一致;若用 MySQL 8 的 caching_sha2_password,老版本 MHA(0.56 及以前)会连不上从库校验复制位点 - 如果主库宕机前刚写入事务但还没刷盘,MHA 会选一个
Exec_Master_Log_Pos最大的从库——这不等于数据最新,得靠relay_log_info_repository = TABLE+sync_relay_log = 1降低丢事务概率
masterha_manager 进程不能后台化运行
很多人用 nohup masterha_manager & 启动,结果切完发现没反应,因为:
-
masterha_manager是单次运行型程序,不是守护进程;它只做一次健康检查 + 切换,然后退出 - 真要“常驻”,得用
systemd或supervisord拉起,并配置Restart=always和RestartSec=10,否则进程挂了就彻底失守 - 日志必须定向到文件(如
--log=/var/log/mha/app1.log),默认输出到 stdout,后台运行后全丢
典型 systemd 单元片段:
[Service] Type=simple ExecStart=/usr/bin/masterha_manager --conf=/etc/mha/app1.cnf Restart=always RestartSec=10 StandardOutput=append:/var/log/mha/app1.log StandardError=append:/var/log/mha/app1.log
切换后应用连不上,大概率是 DNS 缓存或连接池没刷新
VIP 切过去不代表业务立刻可用:
- JDBC 连接串里写死 IP 就别指望自动切,得用域名(如
db-master.example.com)并配极短 TTL(30 秒以内),还要关掉 JVM 的networkaddress.cache.ttl - Spring Boot 的 HikariCP 默认缓存 DNS,得加参数
datasource.hikari.connection-init-sql=SELECT 1并设connection-test-query,否则旧连接池还在往老地址发包 - PHP 的
mysqlnd有内置 DNS 缓存,mysqli实例创建后不会重新解析,必须重启 PHP-FPM 或用mysqli::change_user()强制重连
最简单的验证方式:切换后,在应用服务器上立刻 dig db-master.example.com 和 telnet db-master.example.com 3306,两个都通才真正就绪。
真正麻烦的从来不是 MHA 装好没,而是 VIP 怎么不飘、DNS 怎么不卡、连接池怎么不僵——这些环节没对齐,切完比不切还糟。


















