mha无法保证零丢失,因其不控制mysql日志刷盘行为,真正决定数据是否丢失的是sync_binlog=1和innodb_flush_log_at_trx_commit=1等底层配置;异步复制下主库宕机未传binlog必丢,mha仅能通过gtid对比选最接近的从库并补偿日志,但彻底宕机时仍需人工校验一致性。

MHA 无法保证 0 丢数据,但能最大限度减少丢失 —— 关键在于主库是否开启 sync_binlog=1 和 innodb_flush_log_at_trx_commit=1,且从库必须启用 relay_log_info_repository=TABLE 和 master_info_repository=TABLE。
为什么“0丢数据”是条件性目标,不是默认结果
MHA 自身不控制 MySQL 的日志刷盘行为,它只负责故障检测、选主、日志补偿和角色切换。真正决定能否不丢事务的是底层 MySQL 配置:
-
sync_binlog=1:确保每个事务的 binlog 都落盘,否则主库宕机时未刷盘的 binlog 会丢失 -
innodb_flush_log_at_trx_commit=1:确保每个事务的 redo log 同步写入磁盘,避免崩溃后事务回滚不可逆 - 若主库用的是异步复制(默认),且刚提交一个事务、binlog 还没传到从库就宕机 → 这个事务必然丢失,MHA 无能为力
- MHA 的
save_binary_logs工具只能抢救主库磁盘上已写入但未复制出去的 binlog,前提是主库还能 SSH 连上(即“假死”而非彻底断电)
如何让 MHA 尽可能接近“不丢数据”的切换效果
这不是改 MHA 配置就能解决的问题,而是要组合 MySQL 复制模式 + MHA 行为 + 网络保障:
- 必须使用 GTID 复制(非传统 position),否则
apply_diff_relay_logs无法精准定位差异起点 - 所有从库开启
relay_log_recovery=ON,避免 relay log 损坏导致同步中断 - 在 MHA 配置中设置
check_repl_delay=0,防止因从库延迟被跳过选主(但需配合candidate_master=1显式指定可信从库) - 配置
secondary_check_script,用多路径探测主库(比如同时走管理网和业务网),避免单点网络抖动误判 - 禁用
shutdown_script中的强制 kill,改用mysqladmin shutdown,给主库留出刷盘时间窗口(仅适用于可预知的维护场景)
当主库彻底宕机(SSH 不通)时,MHA 怎么选最优从库
此时 save_binary_logs 失效,MHA 只能依赖从库之间 relay log 的 GTID 集合对比,选出最接近主库状态的那个:
- 优先比较
SELECT @@GLOBAL.gtid_executed,取并集最大者 - 若 GTID 相同,再比
SHOW SLAVE STATUS\G中的Exec_Master_Log_Pos(仅限非 GTID 模式备用) - 注意:
Seconds_Behind_Master不可靠 —— 它可能为 0,但 SQL thread 实际卡在某个 DDL 上 - 如果所有从库都落后较多,MHA 仍会选一个提升,但后续需人工校验
gtid_purged是否一致,否则新主库无法被原主库反向接入为从库
最容易被忽略的三个落地细节
很多团队配完 MHA 能切,但一出事就丢数据,问题往往卡在这三处:
- MySQL 用户权限没给全:
GRANT REPLICATION SLAVE, REPLICATION CLIENT, SUPER ON *.* TO 'mha_user'@'%'—— 少SUPER权限会导致save_binary_logs失败 - MHA Manager 节点时间不同步:NTP 未校准会导致
masterha_master_monitor判断超时异常,或日志时间戳错乱影响故障分析 - 没有预置
master_ip_failover_script:MHA 切换后 VIP 不漂移,应用连的还是旧 IP,看起来“切成功了”,实则流量没过去











