innodb_log_buffer_size过小导致高并发写入时logbuffer溢出,表现为innodb_log_waits增长、事务提交变慢;默认16mb不足,需据写入速率调至32m~128m并重启生效。

不是磁盘慢,是 innodb_log_buffer_size 太小卡住了写入节奏。 你看到事务提交变慢、innodb_log_waits 持续上升、innodb_os_log_written 增速异常高,基本可以确定是这个缓冲区在拖后腿——它默认只有 16MB,在批量 INSERT 或高频小事务场景下,几毫秒就填满,被迫频繁刷盘。
怎么确认真是 innodb_log_buffer_size 的问题
别猜,直接查指标:
-
SHOW GLOBAL STATUS LIKE 'innodb_log_waits';—— 如果值 > 0 且随时间增长,说明缓冲区已溢出,InnoDB 正在阻塞等待刷盘 -
SHOW GLOBAL STATUS LIKE 'innodb_os_log_written';—— 每隔 10 秒执行一次,算差值除以 10 得到 MB/s 写入速率;再乘以 2~3 倍,就是innodb_log_buffer_size的合理下限(比如测得 40MB/s,建议至少设为 128MB) - 观察
SHOW ENGINE INNODB STATUS\G中的 Log section,如果 “Log sequence number” 和 “Last checkpoint at” 差值长期占总日志空间 70% 以上,说明日志系统整体承压,但根源常在 buffer 不够攒批
设多大才合适:32M~128M 是安全起步区间
这不是越大越好,而是要匹配你的写入节奏和内存余量:
- 中小负载(QPS
- 高并发写入(如订单、日志类业务)或批量导入:建议 64MB~128MB
- 超过 256MB 要谨慎:这块内存是全局独占、不可复用的,设太大可能挤占
innodb_buffer_pool_size,反而引发 swap - 绝对不能 SET GLOBAL 动态改:
SET GLOBAL innodb_log_buffer_size = 67108864;会报错,必须修改配置文件后重启 MySQL 才生效
单调 innodb_log_buffer_size 没用,必须配齐三个参数
只调 buffer 就像只加油不换轮胎——压力会立刻转移到其他环节:
-
innodb_log_file_size:必须 ≥innodb_log_buffer_size的 4 倍。例如 buffer 设为 64MB,log file 至少要 256MB。否则 checkpoint 频繁,buffer 攒的批还没用完就被迫刷走 -
innodb_flush_log_at_trx_commit:设为 1(每次 commit 都 fsync)时,buffer 小 = 反复强制刷盘;设为 2(每秒刷一次)时,buffer 可更大胆地攒批,性能提升更明显 -
innodb_flush_method:避免用O_DSYNC,推荐O_DIRECT或留空(默认)。否则 OS cache 和 InnoDB buffer 双重缓存,反而增加开销
最容易被忽略的两个坑
很多人调完就上线,结果性能没起色甚至更差,大概率栽在这两处:
- 把
innodb_log_buffer_size和innodb_log_file_size搞混:前者是内存里的缓冲区,后者是磁盘上 ib_logfile0/1 文件大小。改错地方等于白调 - 改
innodb_log_file_size前没删旧日志文件:MySQL 启动时发现 ib_logfile 大小和配置不一致,会直接拒绝启动,报错类似log file size mismatch
真正卡住 Redo Log 写入的,往往不是磁盘本身,而是 buffer 没给够“喘息时间”。调参不是拍脑袋,得看 innodb_log_waits 是否为零、写入速率是否匹配 buffer 容量、配套参数是否协同——漏掉任意一环,都可能让优化变成负优化。











