先查主库rpl_semi_sync_master_off_times是否每分钟涨1次以上,若持续增长则确认退化发生,再结合error log中“timeout waiting for slave ack”及其前后网络或io上下文定位根因。

半同步复制超时不是“插件坏了”,而是主库在说:“我等不到 ACK 了”。直接查 Rpl_semi_sync_master_off_times 是否上涨,再结合 error log 里 Timeout waiting for slave ACK 的上下文,才能定位真因——调大 rpl_semi_sync_master_timeout 只是掩盖问题,不是修复。
怎么看主库是否真在退化?
别一上来就翻日志。先连主库执行:
SHOW STATUS LIKE 'Rpl_semi_sync_master_off_times';
如果这个值每分钟涨 1 次以上,说明退化正在发生;如果一直是 0,那压根没触发半同步降级,日志里也不会有相关记录。
-
Rpl_semi_sync_master_off_times每 +1,代表主库主动关闭半同步一次,对应日志中至少一条Timeout waiting for slave ACK - 如果
Rpl_semi_sync_master_wait_timeouts飙升但Rpl_semi_sync_master_off_times不涨,说明事务在重试(比如设了 3 次重试),但还没到“关插件”阈值,日志可能只有 WARNING 级别,没有 ERROR - 同时查
Rpl_semi_sync_master_clients:值为 0 表示主库根本没收到任何从库的半同步声明,可能是从库没开rpl_semi_sync_slave_enabled,或网络不通导致握手失败
error log 里该 grep 什么?怎么 grep 才不漏线索?
错误日志不会写“半同步已退化”,只记录超时事件、ACK 接收线程异常和网络报错。关键是要抓上下文,不是孤立关键词。
- 必须用主库的 error log 路径,比如
/var/log/mysql/error.log;从库日志里查不到退化依据 - 别只
grep "semi"—— 容易漏掉真正诱因。推荐:grep -A 5 -B 5 "Timeout waiting for slave ACK" /var/log/mysql/error.log - 重点看前后是否紧跟着:
Got timeout reading communication packets、Aborted connection或thread_id=.*ack_receiver - 如果看到
Got an error reading communication packets后紧跟Timeout waiting for slave ACK,基本锁定是网络层丢包,或从库 TCP 接收队列满(可用ss -i查rcv_space是否长期接近rmem)
怎么区分是网络延迟还是从库 IO 卡住?
同一句 Timeout waiting for slave ACK 可能对应两种完全不同的根因:ACK 没发出来,还是发了但主库没收着?得靠从库状态交叉验证。
- 登录从库执行
SHOW PROCESSLIST,如果State长期卡在Waiting for master to send event,且Slave_IO_Running: Yes,说明 ACK 根本没发出 → 问题在从库 IO 线程或磁盘刷 relay log 慢(检查sync_relay_log=1和磁盘 I/O util) - 如果
State是Queueing master event to the relay log或Reading event from the relay log,说明 ACK 已发,但主库没收到 → 优先查主从间网络 RTT 峰值、中间防火墙/负载均衡丢包、TCP 重传率 - 注意
rpl_semi_sync_master_wait_point设置:若为AFTER_COMMIT,主库提交后才等 ACK;若为AFTER_SYNC,则等 binlog 写盘后再等 ACK —— 后者对磁盘压力更敏感,也更容易被 IO 卡住拖慢
为什么调大 rpl_semi_sync_master_timeout 往往治标不治本?
它单位是毫秒,设值必须落在真实网络与负载的波动区间内。盲目拉高只会让单事务延迟不可控,甚至掩盖底层恶化。
- 局域网环境(RTT 稳定在 0.5–2ms):设
1000是合理起点,覆盖 99% 抖动尖峰 - 跨机房或高负载场景(RTT 偶尔飙到 15ms+):可设
3000~5000,但别碰10000(默认值),否则事务平均延迟可能突破 10 秒 - 绝对不要设低于
500:哪怕 ping 延迟只有 0.3ms,UDP 小包丢包率 >0.1% 时,100ms 超时也会频繁触发降级 - 改完立刻生效:
SET GLOBAL rpl_semi_sync_master_timeout = 3000;,无需重启
真正要稳住半同步,得盯住 ACK 是谁发的、什么时候发的、发了之后哪一环断了——而不是让主库等得更久。











