超时退化不是故障而是信号,反映ACK未按时返回,主库状态在ON/OFF间跳变说明等待条件不稳定;需结合网络RTT、从库IO负载、参数组合(如AFTER_SYNC/AFTER_COMMIT)及底层系统配置综合调优,而非单纯调大timeout。

直接调大 rpl_semi_sync_master_timeout 不是解法,反而可能掩盖真实问题、放大延迟风险。真正要做的,是让半同步“稳得住”,而不是“等得久”。
为什么超时退化不是故障,而是信号
主库状态在 Rpl_semi_sync_master_status=ON 和 OFF 之间反复跳变,本质是它在告诉你:某个环节卡住了——不是插件没开,而是 ACK 没按时回来。这个机制本身没问题,问题出在等待条件不稳定。
- 常见诱因包括:
rpl_semi_sync_master_timeout设为 10 或 100 毫秒(远低于实际 RTT 峰值) - 从库 TCP 接收队列积压,
net.ipv4.tcp_rmem过小,导致小包(如 ACK)被丢或延迟 - 主从间混跑备份流量或大查询,瞬时带宽打满,ACK 包被压在队列尾部
- 从库上
slave_parallel_workers > 0但slave_parallel_type仍是默认的DATABASE,SQL 线程未执行完就发了 ACK
怎么设 rpl_semi_sync_master_timeout 才合理
它不是越长越安全,也不是越短越“强一致性”。它的单位是毫秒,设值必须落在网络与负载的真实波动区间内。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 局域网环境(RTT 稳定在 0.5–2ms):设为
1000(1 秒)是起点,能覆盖 99% 的抖动尖峰 - 跨机房或高负载场景(RTT 偶尔飙到 15ms+):可设为
3000~5000,但别碰10000(默认值),那会把单事务延迟拉到不可接受 - 绝对不要设低于
500:哪怕 ping 延迟只有 0.3ms,UDP 小包丢包率 >0.1% 时,100ms 超时也会频繁触发降级 - 改完立刻生效:
SET GLOBAL rpl_semi_sync_master_timeout = 3000;,无需重启
光调 timeout 不够,还得盯住 ACK 是谁发的
Rpl_semi_sync_master_status=ON 只表示“至少有一个从库连上了且声称支持半同步”,不代表你依赖的那个从库真在参与。
- 查主库当前有几个半同步客户端:
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients'; - 挨个登录每个从库,确认两件事都为
ON:rpl_semi_sync_slave_enabled和Rpl_semi_sync_slave_status - 重点看
Rpl_semi_sync_master_no_times(累计降级次数)和Rpl_semi_sync_master_off_times(累计关闭次数):如果这两个值每小时涨几十次,说明不是参数问题,是网络或从库 IO 已经扛不住 - 此时该查从库的
SHOW PROCESSLIST,重点关注Slave_IO_Running: Yes但Seconds_Behind_Master持续增长,或者State卡在Waiting for master to send event—— 那就是从库接收线程被堵了
容易被忽略的底层陷阱
很多性能问题藏在参数组合里,表面无关,实则共振放大延迟。
-
rpl_semi_sync_master_wait_point = AFTER_COMMIT:主库先提交再发 binlog,崩溃后可能丢已确认事务;还容易和sync_binlog=1冲突,触发双刷盘 -
sync_binlog=1+innodb_flush_log_at_trx_commit=1+ 半同步:三重落盘 + 等 ACK,单事务延迟轻松破 10ms,尤其 SSD 负载高时 - 从库开了并行复制但没配
slave_parallel_type=LOGICAL_CLOCK:ACK 在 relay log 写入缓冲区就发出,而非真正写入磁盘,导致“伪半同步” - 防火墙或中间设备对
ACK这类小包做了限速(比如每秒最多 100 个),而你的 QPS 超过这个阈值,ACK 就必然排队
真正稳定的半同步,不靠死等,靠精准识别谁在响应、谁在拖后腿、以及网络是否真的可信。一旦发现 Rpl_semi_sync_master_off_times 在缓慢但持续上升,别急着调 timeout,先抓包看 ACK 到底卡在哪一层。

















