真正起作用的是后台刷页行为是否平稳,需结合innodb_adaptive_flushing=on、匹配磁盘iops的innodb_io_capacity、合理设置innodb_lru_scan_depth、关闭ssd上的innodb_flush_neighbors,并验证innodb_pages_written抖动下降20%+、innodb_os_log_pending_fsyncs不攀升、buf_pool_lru_scan_depth单次扫描耗时

调 innodb_max_dirty_pages_pct 不等于解决刷页抖动,真正起作用的是它触发的后台行为是否平稳——而这个行为受磁盘能力、自适应算法、NUMA绑定等隐性条件共同制约。
怎么看脏页比例是否真高?别只信静态百分比
监控 innodb_buffer_pool_pages_dirty / innodb_buffer_pool_pages_total 得到的只是一个快照值,容易误判。比如长事务钉住 flush_list,脏页占比可能长期卡在 78%,但实际刷页线程根本没在干活。
- 优先看每秒变化:用
information_schema.INNODB_METRICS查buffer_pool_dirty_pages和buffer_pool_flushed_pages的 delta,持续 >500/s 且buffer_pool_wait_free上涨,才是真压力 - 结合 redo log 压力:执行
SHOW ENGINE INNODB STATUS\G,关注 LOG 段中log sequence number和log flushed up to差值是否 >1GB;History list length 是否持续增长 - 查实时阻塞源:运行带
trx_weight过滤的关联查询,重点盯trx_weight > 10000且trx_started超过 60 秒的事务
为什么改了 innodb_max_dirty_pages_pct 却没效果?
常见原因不是参数没生效,而是刷页节奏被其他开关卡死:
-
innodb_adaptive_flushing = OFF:此时刷页完全靠脏页比例触发,不响应 redo log 生成速率;高频写入下极易滞后,必须设为ON -
innodb_io_capacity远低于磁盘真实 IOPS:SSD 实测随机写 3200 IOPS,却还用默认 200,再调innodb_max_dirty_pages_pct也没用 -
innodb_lru_scan_depth过高:默认 1024,在高并发写入下会引发 LRU 链表扫描锁争用;SSD 可压到 256,HDD 建议 ≤128 - NUMA 绑定失效:
numastat -p $(pgrep mysqld)显示numa_hit ,说明刷页内存分配跨节点,引发延迟毛刺
SSD 环境下必须关掉 innodb_flush_neighbors
这个参数在 HDD 上能合并随机写为顺序写,但在 SSD 上毫无收益,反而浪费 I/O 带宽、拉高延迟。
- 确认存储类型:
cat /sys/block/*/queue/rotational输出0表示 SSD - 动态关闭:
SET GLOBAL innodb_flush_neighbors = 0 - MySQL 5.7 默认开启,SSD 环境务必手动关掉——否则即使
innodb_max_dirty_pages_pct设对了,刷页也会因无效邻页扫描拖慢
验证刷页是否真的变稳?看这三项指标
改完配置后,不能只跑 SHOW VARIABLES LIKE 'innodb_max_dirty_pages_pct' 就收工。要观察实际行为:
-
Innodb_pages_written每秒增量是否更平稳:抖动下降 20%+,且业务 SQL 延迟无上升 -
Innodb_os_log_pending_fsyncs是否不再持续攀升:说明刷脏没滞后,redo log 循环正常 -
SHOW ENGINE INNODB STATUS\G中BUF_POOL_LRU_SCAN_DEPTH单次扫描耗时是否 innodb_lru_scan_depth 还没调到位)
最复杂的点往往不在参数本身,而在多个耦合变量之间的节奏匹配——比如把 innodb_max_dirty_pages_pct 设到 75,却忘了同步调高 innodb_io_capacity,结果刷页线程始终“饿着”,后台永远追不上写入速度。











