rpl_semi_sync_master_status 变为 off 是主库超时未收 ack 后主动降级的保命机制,并非故障;默认超时 10 秒,rtt 峰值达 15ms 时设 100ms 必退化;ack 由从库写完 relay log 并 fsync 后发出,非连接即发;错误日志不记录状态切换,需通过 "timeout waiting for slave ack" 及关联线程 id 和网络异常线索定位;必须在主库查状态变量确认真实半同步状态。

Rpl_semi_sync_master_status 变成 OFF 不是出错了,是主库按设计主动切的——只要没在 rpl_semi_sync_master_timeout 毫秒内收到至少一个从库的 ACK,它就立刻退化为异步,继续处理请求。这不是故障,是保命机制。
超时等待失败是唯一触发退化的直接原因
主库事务提交后,会阻塞并等待 ACK;超时即降级,没有例外,也不需要从库宕机或网络断开。
-
rpl_semi_sync_master_timeout默认 10000(10 秒),但实测 RTT 峰值若达 15ms,设 100 就必退化 - 一次超时 ≠ 一次降级:
Rpl_semi_sync_master_wait_timeouts上涨只代表“单次事务重试失败”,而Rpl_semi_sync_master_off_times涨 1 才代表真关了一次半同步 - ACK 是从库
slave_io_thread写完 relay log + fsync 后发的,不是连上就发——如果从库磁盘慢、sync_relay_log=0或innodb_flush_log_at_trx_commit=2,ACK 就会晚
日志里根本不会写“已退化”,线索全靠上下文拼凑
错误日志不记录状态切换,只记事件:插件加载、超时、ACK 失败。关键要抓时间戳和线程 ID 关联。
- 搜
"Timeout waiting for slave ACK"必须带前后文: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—— 这是主库专收 ACK 的线程,它卡住或退出,等于直接废掉半同步
从库一切正常?那更得查主库状态变量
SHOW SLAVE STATUS 在从库上跑得再漂亮,也掩盖不了主库早已 Rpl_semi_sync_master_status = OFF 的事实。
- 必须登主库查:
SHOW STATUS LIKE 'Rpl_semi_sync_master_status';(当前态)、Rpl_semi_sync_master_off_times(退了多少次)、Rpl_semi_sync_master_clients(真有几个从库在参与) -
Rpl_semi_sync_master_clients返回 0?说明从库根本没声明支持半同步——可能插件没装、rpl_semi_sync_slave_enabled = 0,或复制连接被防火墙拦了 - 如果
Rpl_semi_sync_master_off_times每小时涨几十次,别调 timeout,先查从库SHOW PROCESSLIST里Slave_IO_Running: Yes但 State 卡在Waiting for master to send event—— 那是 ACK 根本没发出来











