MySQL半同步复制不能完全防止主从切换丢数据,仅能大幅降低概率;它只保证至少一个从库收到并写入relay log,不保证已执行或提交,若切换到未执行事务的从库仍会丢数据。

MySQL半同步复制到底能不能防主从切换丢数据
不能完全防,但能大幅降低概率——前提是正确启用且监控到位。半同步不是开关一开就万事大吉,它只保证至少一个从库收到了 binlog 并写入 relay log(或磁盘),不保证已执行、不保证事务已提交。主库 crash 后若选了一个还没来得及执行的从库做新主,照样丢数据。
-
rpl_semi_sync_master_enabled和rpl_semi_sync_slave_enabled必须都为ON,缺一不可 - 从库必须运行
START SLAVE IO_THREAD(半同步依赖 IO 线程上报 ACK) -
rpl_semi_sync_master_timeout建议设为 10000(10 秒),太短会导致频繁退化为异步,太长会拖慢主库响应
如何确认半同步真的在生效
光看变量值是假象,得查实时状态和日志。常见错误是配置完没验证,切主时才发现一直 fallback 到异步模式。
- 执行
SHOW STATUS LIKE 'Rpl_semi_sync%';,重点看Rpl_semi_sync_master_status(应为ON)和Rpl_semi_sync_master_no_tx(非零说明有事务没等 ACK 就提交了,已退化) - 检查错误日志里有没有
Timeout waiting for reply from slave,这是超时退化的直接证据 - 用
mysqlbinlog对比主库最新 binlog position 和从库SHOW SLAVE STATUS\G中的Read_Master_Log_Pos,差太多说明 IO 延迟高,半同步容易失败
主从切换时为什么半同步还是丢了数据
核心问题在于“谁被选为主”和“它执行到哪了”完全脱节。MHA、Orchestrator 这类工具默认只看复制延迟,不校验 SQL 线程执行位点;人工切换更常忽略 Exec_Master_Log_Pos。
- 切主前必须确认候选从库的
Seconds_Behind_Master = 0且Slave_SQL_Running_State = 'Slave has read all relay log' - 优先选
Read_Master_Log_Pos == Exec_Master_Log_Pos的从库,否则即使半同步成功,未执行的事务也会丢失 - 如果所有从库都有执行延迟,宁可先停写、等追平,也不要强行切——半同步保不住“已接收但未执行”的那部分
生产环境必须补的三道防线
半同步只是其中一环,单靠它扛不住真实故障场景。
- 开启
sync_binlog = 1和innodb_flush_log_at_trx_commit = 1,确保主库崩溃时不丢已提交事务的 binlog 和 redo - 部署至少两个从库,并让其中一个专用做“半同步备胎”:设置
super_read_only = ON+skip_slave_start = 1,只收日志不执行,切主前再手动启动 SQL 线程并校验位点 - 用
pt-heartbeat或自建心跳表监控端到端延迟,比Seconds_Behind_Master更准——后者在 SQL 线程卡住时会失真
最容易被忽略的是:半同步的“安全”只存在于主库视角,从库是否真正可靠,得靠你亲自核对执行位点,而不是相信配置开了就万事大吉。


















