半同步让主库卡在“等至少一个从库ack”这一步,即写完binlog并发送后、事务提交前阻塞等待;默认after_sync模式下,主库必须收到ack才提交,超时(毫秒级)则降级为异步。

因为主库必须卡在 commit 前等至少一个从库返回 ACK,而这个 ACK 只代表 relay log 缓冲区写入成功,并不保证落盘或执行完成。
半同步让主库“卡在哪一步”?
默认 rpl_semi_sync_master_wait_point = AFTER_SYNC,主库流程是:写 binlog → 强制刷盘(sync_binlog=1 时)→ 发送给从库 → 等 ACK → 才提交事务。这中间的等待不是可选的,是阻塞式的。只要网络抖动、从库接收队列积压、甚至 TCP window 满了,主库就停在这一步。
- 若设为
AFTER_COMMIT,主库先提交再等 ACK,看似快一点,但主库 crash 后可能已提交却未同步,事务丢失风险上升 -
rpl_semi_sync_master_timeout单位是毫秒,设成 100 就容易频繁降级;设成 10000 又会让单条事务多等 10 秒,QPS 直接受损 - 哪怕从库平均 ACK 耗时只有 20ms,P99 达到 80ms,主库写入延迟也会被拉高到接近该值
哪些配置组合会把延迟放大到不可接受?
不是所有“加强可靠性”的设置都值得开——有些是性能黑洞:
-
sync_binlog=1+innodb_flush_log_at_trx_commit=1+ 半同步:三次强制刷盘叠加等待,单事务延迟轻松突破 10ms,尤其在 SSD 高负载时 -
rpl_semi_sync_master_wait_for_slave_count设为 2 或更高:等于要求两个从库都 ACK,不是高可用,是自设瓶颈 - 从库开了
slave_parallel_workers > 0但没配slave_parallel_type = 'LOGICAL_CLOCK':ACK 发送时机不可控,SQL 线程还没执行完就返回了 relay log 接收确认,导致主库误判“已就绪”
怎么验证 ACK 真正在起作用,而不是假阳性?
别只看 SHOW VARIABLES LIKE 'rpl_semi_sync%' 全是 ON 就以为生效了——那只是开关打开了。
- 查状态变量:
Rpl_semi_sync_master_status是 ON 表示当前处于半同步模式;Rpl_semi_sync_master_no_times和Rpl_semi_sync_master_off_times如果持续增长,说明频繁超时退化,得立刻查从库SHOW PROCESSLIST里 I/O 线程是否卡住 - 用
pt-heartbeat测真实业务延迟:Seconds_Behind_Master = 0 不代表数据已落地,大事务下 SQL 线程还在执行中,但主库早已返回成功 - 抓包验证:在主库 dump 线程发完 event 后,观察是否真等到从库 TCP ACK + 协议层 semi-sync response 才继续
真正影响延迟的从来不是“有没有半同步”,而是“等什么、等多久、等谁”。参数调得太保守,主库寸步难行;调得太激进,又等于没开。关键在监控降级频次和 ACK RTT 分布,而不是堆叠安全配置。











