innodb_flush_log_at_trx_commit=1导致log_sys->mutex争用严重,应调大innodb_log_buffer_size(如64m)并设为2,配合sync_binlog=1及组提交优化,以降低锁竞争、提升吞吐。

因为默认的 innodb_flush_log_at_trx_commit = 1 强制每次事务都触发一次 fsync(),而 log_sys->mutex 是全局串行锁,所有写事务必须排队抢它——QPS 超过 2000 就明显卡住。
为什么 log_sys->mutex 会卡死所有写入
这把锁不是按页、按事务拆分的,它保护的是整个 redo log buffer 的生命周期操作:分配空间、拷贝日志内容、更新内存 LSN、判断是否刷盘。哪怕一个事务只改一行,也得完整走一遍这个临界区。
- INSERT/UPDATE/DELETE → 记 redo → 进
log_sys->mutex临界区 → 出临界区 → 提交返回 - 当
innodb_flush_log_at_trx_commit = 1时,fsync()延迟直接拉长锁持有时间,自旋等待线程在SHOW ENGINE INNODB STATUS中表现为挂起在log_write_up_to或log_flush_up_to -
Innodb_log_waits > 0持续增长,说明innodb_log_buffer_size太小,buffer 频繁溢出,进一步放大 mutex 争抢
innodb_log_file_size 调大没用,真正该动的是哪几个参数
增大 innodb_log_file_size 只影响 checkpoint 频率和 crash recovery 时间,完全不参与 log_sys->mutex 的争用路径。它甚至可能因单次刷盘量变大,拖慢后台 io_thread,间接加重锁等待。
- 必须调大
innodb_log_buffer_size(如设为64M):减少 buffer 溢出频率,降低 flush 触发次数,直接减少 mutex 抢占 - 设
innodb_flush_log_at_trx_commit = 2:日志只写 OS cache,每秒由后台线程统一刷盘;吞吐可提升 3–10 倍,但崩溃最多丢 1 秒数据 - 搭配
sync_binlog = 1且启用组提交(binlog_group_commit_sync_delay = 100,binlog_group_commit_sync_no_delay_count = 10):让 binlog 和 redo 刷盘节奏对齐,避免 binlog 线程“等不到人”就单刷
为什么不能只靠关双一或调 buffer 就完事
单独设 innodb_flush_log_at_trx_commit = 2 而不调 sync_binlog,会导致 binlog 和 redo log 不一致,主从复制可能出错;只调大 innodb_log_buffer_size 却忽略 log_sys->mutex 的本质瓶颈,只是延缓而非解决争用。
-
innodb_flush_log_at_trx_commit = 2+sync_binlog = 0:性能最高,但主从延迟不可控,且 binlog 组提交失效 -
innodb_flush_log_at_trx_commit = 0:完全交由后台线程每秒刷一次,崩溃可能丢失最多 1 秒已提交事务,生产环境基本不用 - Redo log 文件放 SSD 也要注意:别和数据文件共盘;用
noop调度器;挂载选项加barrier=0(仅限有 UPS 或写缓存可靠的 SSD)
最常被忽略的一点是:log_sys->mutex 的争用不会在 slow log 里体现,也不会报错,只会表现为大量线程在 Writing to binlog 或 updating status 状态下“莫名卡住”——得看 SHOW ENGINE INNODB STATUS 的 SEMAPHORES 和 LOG 部分才能定位到根因。











