innodb_log_waits持续上涨是因innodb_log_buffer_size过小与innodb_flush_log_at_trx_commit=1组合引发隐式锁争用,导致缓冲区频繁写满、强制刷盘并阻塞后续事务写入redo log。

Log Buffer 竞争不是“并发太高”,而是 innodb_log_buffer_size 太小 + innodb_flush_log_at_trx_commit=1 组合导致的隐式锁争用,必须协同调参,单改 buffer 无效。
为什么 innodb_log_waits 持续上涨?
这不是磁盘慢,是内存缓冲区反复被写满后强制刷盘,阻塞后续事务写入 redo log。现象包括:
-
SHOW GLOBAL STATUS LIKE 'innodb_log_waits';非零且每秒增长 - 事务提交延迟升高,但
SHOW PROCESSLIST中状态卡在query end或updating -
innodb_os_log_written增速远高于实际业务写入量(说明有大量无效 flush)
怎么安全调大 innodb_log_buffer_size?
它不能动态改,且盲目加大反而浪费内存、拖慢 crash recovery。实操要点:
- 先算:用
innodb_os_log_written10 秒差值 ÷ 10,得 MB/s;乘以 2~3 倍即为 buffer 下限(如 40MB/s → 建议 ≥ 128MB) - 再设:常用值为
67108864(64MB)或134217728(128MB),写进my.cnf的[mysqld]段 - 必须重启 MySQL 生效;
SET GLOBAL innodb_log_buffer_size = ...会报错 - 别超 256MB:buffer 是全局独占内存,不参与 buffer pool 管理,过大无收益
innodb_flush_log_at_trx_commit=1 是 Log Buffer 竞争的放大器
设为 1 时,每个事务提交都触发一次 fsync,buffer 再大也扛不住高频攒批——因为根本没机会攒。真正解法是放宽日志落盘时机:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 设为
2:事务只写 OS cache,后台线程每秒刷一次;此时 buffer 才能真正缓存多事务日志 - 搭配
sync_binlog=1000(非1):避免 binlog 和 redo log 各自刷盘,否则 I/O 翻倍 - 验证是否生效:
SHOW GLOBAL STATUS LIKE 'Innodb_log_fsyncs';÷Innodb_log_writes应 ≤ 0.1;若接近 1,说明仍被架空
容易被忽略的两个硬性依赖
即使参数全调对,Log Buffer 竞争仍可能持续——问题常出在这两处:
-
innodb_log_file_size过小(如默认 48MB):会导致 checkpoint 频繁刷脏页,间接挤占 log buffer 空间;建议单文件 ≥ 256MB,且修改前必须停库删ib_logfile* - OS 层干扰:ext4 默认挂载含
barrier=1,每次 write() 都强制刷盘,抵消组提交效果;SSD 上应挂载加barrier=0并设调度器为none
Log Buffer 竞争本质是“内存缓冲”和“持久化策略”的错配,不是单纯加资源就能解决的问题。最常被跳过的动作是:改完 innodb_log_buffer_size 后没同步调大 innodb_log_file_size,也没验证 Innodb_log_fsyncs / Innodb_log_writes 比值——结果就是白忙一场。










