跨机房网络延迟被半同步复制放大,导致COMMIT响应变慢;启用slave_compressed_protocol=1、BBR拥塞控制和禁用Nagle算法可显著降低ACK延迟。

这不是事务本身变慢了,而是跨机房网络延迟被 MySQL 复制机制放大后,反向拖垮了主库的 COMMIT 响应——尤其在启用半同步复制时。
半同步复制下,COMMIT 等待的是从库确认,不是写入完成
主库执行 COMMIT 时,若启用了半同步(rpl_semi_sync_master_enabled = 1),它必须等至少一个从库返回 ACK,才算提交成功。而这个 ACK 要走完整链路:主库 dump 线程 → 网络传输 → 从库 IO 线程接收并写入 relay log → 从库返回响应。跨机房 RTT 通常 20–80ms,抖动大时单次等待可能超 200ms,直接让 COMMIT 延迟飙升。
- 现象:
SHOW PROCESSLIST中大量线程卡在Waiting for semi-sync ACK from slave - 验证:关掉半同步(
SET GLOBAL rpl_semi_sync_master_enabled = 0),COMMIT延迟立刻回落到毫秒级 - 注意:关半同步不等于丢数据——只要主库
sync_binlog = 1+innodb_flush_log_at_trx_commit = 1,崩溃仍可恢复
slave_compressed_protocol = 1 能降低 30%–50% 的 ACK 往返时间
默认情况下,MySQL 复制流量不压缩,binlog 内容原样传输。跨机房带宽有限、小包密集,TCP 层效率极低。开启压缩后,IO 线程收发的数据量下降,ACK 包更小、更少,网络往返耗时显著减少。
- 仅需在从库配置:
slave_compressed_protocol = 1,然后RESTART SLAVE或SET GLOBAL slave_compressed_protocol = 1 - 不要改主库配置,也不依赖 binlog 格式;MySQL 5.7.9+ 原生支持,旧版本必须升级
- 副作用:从库 CPU 使用率略升(通常
内核级 TCP 优化比 MySQL 参数调整更治本
默认 TCP 行为(Nagle + CUBIC)对高延迟、小包多的复制场景非常不友好:Nagle 算法攒包导致 dump 线程发包延迟,CUBIC 在 RTT >30ms 时带宽利用率暴跌。光调 slave_net_timeout 或 net_read_timeout 解决不了根本问题。
- 主从两端都执行:
sysctl -w net.ipv4.tcp_congestion_control = bbr(Linux 4.9+) - 同时禁用 Nagle:
sysctl -w net.ipv4.tcp_nodelay = 1(MySQL 本身已设 SO_NODELAY,但内核层双重保险) - 效果:同一带宽下,BBR 可将有效吞吐提升 2–3 倍,ACK 往返更稳定,
COMMITP99 延迟下降明显
真正卡住 COMMIT 的,往往不是磁盘或 CPU,而是那几十毫秒飘忽不定的网络往返。别急着调 innodb_log_file_size 或加并行线程——先看 Seconds_Behind_Master 是不是和 COMMIT 延迟同步恶化,再查 Slave_IO_State 是否长期停在 Waiting for master to send event,这才是网络瓶颈的铁证。


















