mysql半同步复制不是强一致,而是等待至少一个从库将binlog事件写入并刷盘relay log后才提交,可降低主库宕机时的数据丢失风险但无法完全避免;其核心是i/o线程落盘即ack,非sql线程执行完成。

MySQL 半同步复制(Semi-Sync Replication)不是“强一致”保障,而是“至少一个从库已落盘 relay log”的确认机制;它不能完全避免数据丢失,但能显著降低主库宕机时未同步事务丢失的概率。
半同步复制的核心行为:ack 必须来自 relay log 刷盘完成
半同步不是等从库执行完 SQL,而是等从库的 I/O Thread 把 binlog event 写入本地 relay log 并调用 fsync() 刷盘后,才发 ACK 给主库。这意味着:
- 即使从库
SQL Thread还没执行(比如被大事务阻塞),只要 relay log 已落盘,主库就认为“数据已安全接收” - 如果从库 crash 后重启,只要 relay log 完整,就能继续重放,不丢事务
- 但若主库在收到 ack 前崩溃,且该事务尚未写入自身 binlog(极端情况),仍可能丢失——所以必须配
sync_binlog=1和innodb_flush_log_at_trx_commit=1
rpl_semi_sync_master_wait_for_slave_count 参数的实际影响
这个参数决定主库要等几个从库返回 ack 才提交,默认是 1。但它不是“等待任意一个”,而是“等待指定数量的在线且启用半同步的从库”。注意:
- 若设为
2,但当前只有 1 个从库在线或启用了rpl_semi_sync_slave_enabled,主库会超时后自动降级为异步,不会卡住 - 超时时间由
rpl_semi_sync_master_timeout控制(单位微秒),默认 10000000(10 秒),超时即切异步,不抛错、不阻塞应用 - 降级后主库日志里会记录
Retrying wait for semi-sync ACKs或Switched to asynchronous replication,需监控
为什么 after_commit 模式在 MySQL 5.6 中有数据不一致风险
MySQL 5.6 默认使用 after_commit 模式:主库先提交事务到存储引擎,再发 binlog 并等 ack。问题在于:
- 若主库提交成功、binlog 已发出、但网络中断导致从库没收到,此时主库宕机,新主库(原从库)会缺失该事务
- 因为事务已在主库提交并返回客户端,但未被任何从库确认,也不在 binlog 中可追溯(binlog 发送失败)
- MySQL 5.7+ 引入
after_sync模式(需显式设置rpl_semi_sync_master_wait_point=AFTER_SYNC),改为“写 binlog + 等 ack → 再提交”,才真正规避该窗口
半同步是否开启成功,不能只看 plugin_status
仅执行 INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so' 和 SET GLOBAL rpl_semi_sync_master_enabled = 1 不代表生效。必须验证:
- 主库上查
SHOW STATUS LIKE 'Rpl_semi_sync_master_status'—— 返回ON才真启用 - 从库上查
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'—— 同样需为ON,且IO_THREAD必须重启(STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;)才能加载半同步逻辑 - 主库
SHOW PROCESSLIST中应出现semi-sync标识的 dump 线程,否则只是插件加载了,没进工作流
真正容易被忽略的是:半同步只对 INSERT/UPDATE/DELETE 等写事务起效,DDL(如 ALTER TABLE)和部分系统操作可能绕过,且一旦网络抖动频繁触发降级,监控不到位就会误以为“一直开着半同步”。











