半同步复制拖慢写入是因为主库commit前必须阻塞等待至少一个从库ack,网络抖动或从库延迟会直接拉高响应时间;合理设置rpl_semi_sync_master_timeout(100–500ms)、保持wait_for_slave_count=1、关闭autocommit并批量事务、优化从库刷盘配置可有效控速。

半同步复制本身就会拖慢写入,但不是不能控——关键在参数调优和事务组织方式。
为什么写入变慢?本质是等待 ACK 的阻塞点
主库执行 COMMIT 时,必须等至少一个从库把 binlog 写入 relay log 并刷盘后返回 ACK,这个等待过程直接卡住事务提交。如果网络抖动、从库负载高或磁盘慢,rpl_semi_sync_master_timeout 超时前都得干等。
-
rpl_semi_sync_master_timeout默认是 10000(10 秒),线上应设为 100–500 毫秒,超时即降级异步,避免雪崩 -
rpl_semi_sync_master_wait_for_slave_count默认为 1;设为 2 虽提升容错,但写入延迟概率翻倍,慎用 - 从库的
relay_log_info_repository = TABLE和sync_relay_log = 1必须开启,否则 ACK 可能不准确
autocommit=ON 是性能杀手,必须关
每个单条 INSERT/UPDATE 都触发一次半同步等待,开销爆炸。MySQL 不会自动合并这些小事务。
- 应用层显式用
START TRANSACTION+COMMIT批量操作,把多条语句包进一个事务里 - ORM 如 MyBatis 需检查是否启用了
autoCommit=false,Spring 的@Transactional默认就是事务块,但要注意传播行为 - 禁止在循环里逐条
INSERT后立即COMMIT,这是典型反模式
从库配置不当会放大延迟,不是主库单方面问题
半同步的瓶颈常卡在从库落盘环节,而非网络传输。relay log 刷盘慢、IO 压力大、甚至 read_only=OFF 导致误写都会让 ACK 滞后。
- 从库务必设
innodb_flush_log_at_trx_commit = 1(保证 crash safe),但sync_binlog可设为 0(从库不生成 binlog) - 关闭从库的
query_cache_type(已弃用但旧配置可能残留),避免锁竞争 - 监控
Seconds_Behind_Master和Slave_SQL_Running_State,若长期显示Reading event from the relay log,说明 SQL 线程跟不上,需优化从库索引或降低主库写压力
别迷信“一致性”,先看业务能否兜底
很多团队加半同步只为防主库宕机丢数据,结果发现写入毛刺频发,反而影响用户体验。其实多数场景下,binlog + GTID + 应用层幂等 的组合比强依赖半同步更轻量、更可控。
真正需要半同步的,是那些无法接受哪怕一行数据丢失的金融类事务;而日志类、统计类、用户行为埋点等写入,完全可以走异步复制+补偿机制。判断标准不是“要不要一致”,而是“出事之后,有没有能力快速回溯、重放、对账”。











