Redo Log组提交通过合并多个事务的fsync显著提升吞吐量:prepare阶段不刷盘,commit阶段由leader线程统一收集、排序并刷盘,依赖两阶段提交及binlog组提交参数协同;需sync_binlog=1,且避免干扰因素如长事务、FLUSH LOGS或innodb_support_xa=OFF。

Redo Log 组提交为什么能提升写入吞吐量
MySQL 的 innodb_flush_log_at_trx_commit=1 下,每事务都刷盘,但磁盘 I/O 是瓶颈;组提交(Group Commit)让多个事务的 redo 日志合并成一次 fsync,显著降低刷盘次数。
关键点在于:InnoDB 在 prepare 阶段不刷盘,而是等 commit 阶段由 leader 线程统一收集、排序、刷盘。这依赖于 binlog 与 redo 的两阶段提交协调,且需 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 配合控制等待窗口。
- 默认
binlog_group_commit_sync_delay=0,几乎不等待,组效果弱;设为 10000(微秒,即 10ms)可明显提升组大小,但会增加平均延迟 -
binlog_group_commit_sync_no_delay_count=10表示凑够 10 个事务就立即刷,不等延时,适合高并发写场景 - 注意:
sync_binlog=1必须开启,否则 binlog 不刷盘,组提交失效
SSD 上 Redo Log 文件放哪更合适
别把 ib_logfile0 和 ib_logfile1 放在跟数据文件同一块 SSD 上——不是因为容量,而是因为混合随机写(redo 是顺序追加但带元数据更新,data 是随机页写)会互相干扰队列深度和 GC 压力。
实操建议:
- 单独挂一块 NVMe SSD(非 SATA SSD),仅挂载为
/var/lib/mysql-redo,把innodb_log_group_home_dir指向它 - 确保该盘使用
noop或noneI/O 调度器(SSD 不需要 CFQ/Deadline),可通过cat /sys/block/nvme0n1/queue/scheduler确认 - 避免 ext4 默认的
barrier=1,改用mount -o barrier=0,errors=remount-ro,noatime(仅限有 UPS 或写缓存可靠的 SSD)
Redo Log 大小设多少才不拖慢写入
innodb_log_file_size 太小会导致频繁 checkpoint,触发 dirty page 刷盘争抢 I/O;太大则 crash 恢复慢,且内存中 log buffer 压力上升。SSD 场景下,重点看日志循环写是否卡住。
判断依据是 SHOW ENGINE INNODB STATUS 中的 Log sequence number 与 Last checkpoint at 差值(即未 checkpoint 的日志量)是否长期接近总日志容量的 70% 以上。
- 线上写入峰值稳定在 50MB/s,建议单个 log file ≥ 1GB(即总日志空间 ≥ 2GB),避免每 40 秒就 checkpoint 一次
- 调整需停库:先
SET GLOBAL innodb_fast_shutdown=0,再关 MySQL,删旧ib_logfile*,改配置,重启 - 不要盲目设到 4GB+:InnoDB 在 recovery 时需扫描全部 redo,SSD 虽快,但 8GB 日志仍可能多花数秒
哪些操作会让 Redo Log 组提交失效
组提交不是自动生效的魔法,以下情况会让事务被迫单独刷盘,破坏吞吐:
- 显式调用
FLUSH LOGS或RESET MASTER,强制同步刷所有 pending redo - 长事务持有
prepare状态太久(比如大事务卡在 binlog 写入),阻塞后续事务进入 commit 阶段 - 开启
innodb_support_xa=OFF(MySQL 5.7+ 默认 ON),会跳过 prepare 阶段,导致无法参与组提交 - 使用
autocommit=0+ 手动COMMIT本身没问题,但如果每个语句后都COMMIT,且间隔很短,反而因锁竞争削弱组效果
真正影响吞吐的,往往不是单次写入速度,而是单位时间里有多少次 fsync 被成功“打包”。SSD 再快,也扛不住每毫秒一次 flush —— 把它压成每 5ms 一次,才是优化的本质。










