MySQL 5.7+默认AFTER_SYNC模式下,主库卡在“等待至少一个从库ACK”这一步:写binlog→刷盘→发event→阻塞等待ACK→再提交;ACK仅表示relay log缓冲区写入成功,不保证落盘或执行完成,网络抖动、从库接收队列满或TCP窗口满均会导致卡顿。

主库卡在 rpl_semi_sync_master_wait_point = AFTER_SYNC 这一步
MySQL 5.7+ 默认启用 AFTER_SYNC 模式,主库事务流程是:写 binlog → 强制刷盘(若 sync_binlog=1)→ 发送 binlog event 给从库 → 阻塞等待至少一个从库返回 ACK → 才提交本地事务。这个“等待 ACK”不是后台异步动作,而是同步阻塞点,只要没收到,事务就挂起。
常见卡住现象包括:SHOW PROCESSLIST 中大量连接状态为 Waiting for semi-sync ACK from slave;QPS 突降、慢查询日志里出现大量超长执行时间的写语句;监控看到 Rpl_semi_sync_master_no_times 或 Rpl_semi_sync_master_off_times 持续上涨。
- ACK 只代表从库已将 event 写入 relay log 缓冲区,不保证落盘、更不保证执行完成
- 网络 RT 高、从库 TCP 接收队列满、内核
net.core.rmem_max过小,都可能导致 ACK 延迟甚至丢包 - 主库不会重试,只等超时(
rpl_semi_sync_master_timeout毫秒),超时即降级为异步,但该次事务已卡住直到超时结束
slave_compressed_protocol=ON 在 MySQL 5.7.19 及更早版本会直接导致 30 秒假死
这不是配置错误,是真实 Bug:半同步模块无法解析压缩协议下的 ACK 包,主库收不到有效响应,只能干等 master_heartbeat_period 超时(默认 30000 毫秒)。错误日志中会出现 Read semi-sync reply magic number error。
- 验证方式:
SELECT @@slave_compressed_protocol;返回ON就要警惕 - 临时修复:在从库执行
SET GLOBAL slave_compressed_protocol = OFF;,并确认主从连接重建 - 根治方案只有两个:升级到 MySQL ≥5.7.21 或 ≥8.0.4;或彻底禁用压缩协议
rpl_semi_sync_master_wait_for_slave_count 设为 2 就是主动加锁
设成 2 意味着主库必须等 两个 从库都返回 ACK 才能提交。但 ACK 不是“执行完”,只是“缓存成功”。任意一个从库稍慢(IO 延迟、relay log 刷盘慢、SQL 线程积压),整个写入链路就被拖住。
- 生产环境建议值永远是
1—— 它是半同步的底线,不是冗余起点 - 如果需要更高可用性,应靠多从库 + 故障自动剔除(如 MHA、Orchestrator),而不是靠提高等待数量
- 监控
Rpl_semi_sync_master_no_times上涨趋势:如果它频繁跳变,说明不是参数问题,而是某台从库真有瓶颈,需立刻查其SHOW PROCESSLIST中Slave_IO_State
哪些组合会让半同步延迟放大到不可接受
单独开半同步未必慢,但和某些“强一致性”配置叠加后,会形成性能黑洞。最典型的是:
-
sync_binlog=1+innodb_flush_log_at_trx_commit=1+ 半同步:三次强制刷盘(binlog、redo、relay log 缓冲区)+ 网络往返,单事务延迟轻松突破 10ms,SSD 高负载时更明显 - 从库开启
slave_parallel_workers > 0但未设slave_parallel_type = 'LOGICAL_CLOCK':并行 worker 可能提前发 ACK,而 SQL 线程还在排队,主库误判“已就绪” -
rpl_semi_sync_master_timeout设得过大(如 10000):单条事务最多卡 10 秒,QPS 直接受损;设得太小(如 100)又导致频繁降级,失去半同步意义
真正卡主库的,从来不是“开了半同步”,而是你让它等什么、等多久、等谁——这些细节没对齐业务实际延迟容忍度,配置再标准也等于自缚手脚。


















