半同步复制让主库写入变慢的根本原因是主库commit必须等待binlog发送完成且至少一个从库返回ack后才响应客户端,涉及rtt延迟与从库relay log刷盘耗时。

半同步复制为什么会让主库写入变慢
根本原因就一个:主库 COMMIT 必须卡在 binlog 发送完成 + 至少一个从库返回 ACK 之后,才能真正返回客户端。这个等待过程不是“发完就走”,而是要等 TCP 往返确认(RTT),还要等从库把事件写进 relay log 并刷盘——中间任何一环延迟,都会直接拖慢你的事务响应时间。
- RTT 越高(比如跨城、跨可用区部署),单次等待越长;RDS MySQL 默认同城专线 RTT 通常
- 从库负载高、磁盘慢、relay log 刷盘慢(
sync_relay_log=1且磁盘 IOPS 不足),会导致 ACK 延迟加剧 - 大事务会阻塞整个 dump 线程,后续小事务全部排队等它传完,形成“写入毛刺”甚至秒级卡顿
rpl_semi_sync_master_timeout 设为多少才合理
这个超时参数不是越小越好,也不是越大越稳——它本质是“性能和可靠性之间的开关”。设得太小(如 100ms),网络轻微抖动或从库短暂 IO 峰值就会触发退化为异步复制,你白开了半同步;设得太大(如 5s),主库会持续卡住,业务明显感知到慢 SQL 或连接堆积。
- RDS MySQL 默认值是
1000(1 秒),适合大多数同城双机房场景 - 若主从同机房且网络稳定,可尝试调低至
500(500ms),加快降级响应,避免长时间卡死 - 若从库偶尔有批量导入或备份压力,建议观察
Seconds_Behind_Master和Rpl_semi_sync_master_no_times状态变量,再决定是否放宽到2000 - 切忌设为
0:MySQL 会拒绝启动半同步,且该值无实际意义
怎么判断性能下降真是半同步导致的
别一看到慢就怪半同步。先确认是不是它背锅:关键看主库有没有频繁“退化”、以及慢是否集中在 COMMIT 阶段。
- 执行
SHOW STATUS LIKE 'Rpl_semi_sync%';,重点看:Rpl_semi_sync_master_no_times(退化次数)是否持续增长;Rpl_semi_sync_master_yes_times是否远低于总提交数 - 用
pt-query-digest分析 slow log,筛选出COMMIT类型的慢语句,再比对其耗时是否接近rpl_semi_sync_master_timeout值 - 检查
SHOW PROCESSLIST中是否有大量线程卡在Waiting for semi-sync ACK from slave状态 - 对比关闭半同步前后
innodb_rows_inserted和Com_commit的 QPS 变化,降幅 >15% 才值得深挖
大事务+半同步=雪崩?如何规避
大事务本身不危险,但它是半同步最怕的“放大器”:一个 100MB 的 binlog event,dump 线程全速传也要几百毫秒,期间所有新事务都得排队等 ACK,主库瞬间“假死”。
- 业务层拆分:单次写入控制在
1000行以内,避免INSERT ... SELECT或UPDATE全表扫描类大操作 - DBA 层监控:用
performance_schema.events_statements_history_long抓取执行时间 >500ms 的COMMIT,关联查出对应事务的原始语句 - 配置兜底:设置
max_binlog_size=256M(而非默认 1G),让大事务自动切多个 binlog 文件,缓解单次传输压力 - 紧急时临时降级:执行
SET GLOBAL rpl_semi_sync_master_enabled = OFF;,但必须同步通知运维,避免 HA 切换时数据丢失










