group commit 提升吞吐量的本质是合并多次 fsync() 为一次,需 sync_binlog=1 且 innodb_flush_log_at_trx_commit=2 才生效;若两者均为 1,则二阶段提交串行化,组提交失效。

Group Commit 提升吞吐量,本质是把多次磁盘 fsync() 合并成一次 —— 不是“变快了”,而是“少刷了”。
硬盘 fsync() 是高延迟操作,尤其在机械盘或高负载 SSD 上。MySQL 5.7 的 Binlog Group Commit 把多个事务的 binlog 写入请求攒成一组,共用一次 fsync(),直接砍掉 80%+ 的刷盘开销。但这个效果**不自动生效**,得看配置是否“放行”。
sync_binlog=1 + innodb_flush_log_at_trx_commit=1 会废掉组提交
这是最常踩的坑:两个参数都设为 1,等于强制每个事务各自完成 binlog 和 redo log 的完整刷盘流程,Binlog_group_commit_trigger_count 基本为 0,组提交形同虚设。
-
sync_binlog=1:要求 binlog 每次 commit 都fsync() -
innodb_flush_log_at_trx_commit=1:要求 redo log 每次 commit 都fsync() - 两者叠加 → 二阶段提交被“串行化”,leader 事务刷完,follower 只能排队等,组提交退化为单线程提交
真正起效的组合:sync_binlog=1 + innodb_flush_log_at_trx_commit=2
这个搭配让组提交有空间运作:
- redo log 只写到 OS 缓存(
innodb_flush_log_at_trx_commit=2),不立即fsync(),释放 InnoDB 层瓶颈 - binlog 仍强制落盘(
sync_binlog=1),但由 leader 统一调度整组fsync() - 只要事务到达时间足够接近,就能被打包进同一个 sync 队列
压测时观察 SHOW GLOBAL STATUS LIKE 'Binlog_group_commit_trigger_count',值稳定增长才说明真在打包。
别只盯 delay,还要看 no_delay_count 和锁竞争
binlog_group_commit_sync_delay 设太大(比如 500000 微秒),小事务平均卡 500ms 才提交,延迟爆炸;设太小(比如 0),又容易因事务到达不密集而打包失败。
-
binlog_group_commit_sync_no_delay_count是保底机制:凑够 N 个就立刻提交,不管 delay 到没到 - 如果
Binlog_group_commit_trigger_lock_wait持续上涨,说明事务卡在 MDL 锁或行锁上,根本进不了 flush 队列 —— 此时调 delay 没用,得查慢日志里Lock_time高但Query_time短的语句
组提交只省 I/O,不解决锁、CPU 或 buffer pool 争用。高频小事务下,InnoDB 的 log_sys->mutex、buf_pool_mutex 或自适应哈希索引(AHI)可能比刷盘还先成为瓶颈。











