vm.dirty_ratio / dirty_background_ratio 写脏页过多导致卡顿的调优

13次阅读

vm.dirty_ratio 和 vm.dirty_background_ratio 引发卡顿的直接原因是:脏页超 vm.dirty_background_ratio 时后台刷盘启动,超 vm.dirty_ratio(默认 20%)则写操作被阻塞;现代大内存与磁盘吞吐不匹配导致 100GB 脏页刷盘耗时数分钟,引发 wa% 飙升、D 状态进程堆积。

vm.dirty_ratio / dirty_background_ratio 写脏页过多导致卡顿的调优

为什么 vm.dirty_ratiovm.dirty_background_ratio 会引发卡顿

Linux 内核用这两个参数控制脏页(被修改但尚未写入磁盘的内存页)的积压上限。当脏页总量超过 vm.dirty_background_ratio(默认 10),内核在后台启动 pdflushwriteback 线程开始异步刷盘;一旦突破 vm.dirty_ratio(默认 20),所有新写操作会被阻塞,直到脏页降到该阈值以下——这就是“突然卡住”的直接原因,尤其在突发大量小文件写、日志刷盘或数据库 checkpoint 场景下极易触发。

  • 典型现象:topwa% 暴涨,iostat -x 1 显示 %util 接近 100% 且 await 超高,ps aux | grep "D" 可见大量 D 状态进程(不可中断睡眠)
  • 根本矛盾:默认值按总内存比例计算,但现代服务器内存大(如 512GB)、而磁盘吞吐有限(如单块 SATA SSD 约 500MB/s),20% 就是 100GB 脏页,全刷完可能耗时数分钟
  • vm.dirty_ratio 是硬上限,触达即阻塞;vm.dirty_background_ratio 是软启动点,差值越小,后台刷盘越激进,但也越容易抢占 I/O 资源

怎么设才不卡:看负载类型选策略

不能只盯着百分比,得结合实际写负载节奏和存储能力。关键不是“调低”,而是让脏页生成速度 ≤ 后台持续刷盘能力。

  • 高吞吐顺序写(如 Kafka 日志、视频转码输出):
    → 适当提高 vm.dirty_background_ratio(如 15)+ vm.dirty_ratio(如 25),配合增大 vm.dirty_expire_centisecs(如 6000,即 60 秒),避免频繁触发刷盘打断写流
  • 随机小写 + 高延迟敏感(如 OLTP 数据库、容器化微服务):
    → 压低两参数(如 vm.dirty_background_ratio=5vm.dirty_ratio=10),并缩短 vm.dirty_writeback_centisecs(如 500,即 5 秒),让脏页更早、更碎地刷出,减少单次阻塞风险
  • 混合负载(如 K8s 节点跑多种工作负载):
    → 折中设为 vm.dirty_background_ratio=10vm.dirty_ratio=15,并务必启用 vm.swappiness=1(抑制 swap,防止脏页和 swap 争内存)

调参后必须验证的三件事

改完 sysctl 不等于生效,也不代表问题消失。要确认内核真正按预期行为运行。

  • 检查是否加载:sysctl vm.dirty_background_ratio vm.dirty_ratio,确保输出值与配置一致;若未生效,执行 sysctl -p
  • 观察实时脏页压力:grep -i dirty /proc/meminfo,重点关注 Dirty:Writeback:PagesDirty:,对比 MemTotal 看是否长期贴近 vm.dirty_ratio 限值
  • 验证刷盘节奏:echo 1 > /proc/sys/vm/drop_caches 后做一次可控写测试(如 dd if=/dev/zero of=/tmp/test bs=1M count=2000 oflag=direct),用 iostat -x 1 看 write 出现是否平滑、有无突刺式长 await

容易被忽略的关联项

单独调这两个参数常治标不治本,以下三点不处理,调了也白调。

  • vm.dirty_ratio 的单位是“占 MemTotal 的百分比”,但若启用了 cgroup v2 memory controller,容器内看到的 MemTotal 是其 memory.max 限制值,此时脏页上限按容器限额算——K8s 默认不限制 memory,但很多生产环境会设 limit,导致容器内脏页更快触顶
  • SSD/NVMe 场景下,vm.dirty_background_ratio 设太低(如 3)反而增加 I/O 次数,降低吞吐;应优先调 vm.dirty_writeback_centisecs 控制刷盘频率,而非一味压低比例
  • 某些发行版(如 RHEL 8+/CentOS 8+)默认启用 systemdMemoryMax,会覆盖全局 vm.dirty_* 设置,需在 /etc/systemd/system.conf 中显式设置 DefaultLimitMEMLOCK=infinity 并重启 systemd

实际卡顿往往不是参数错,而是没意识到脏页行为已随硬件 (NVMe 队列深度)、调度器(BFQ vs mq-deadline)、甚至文件系统(XFS 的 logbsize)联动变化。调参只是入口,背后得连着 I/O 栈一起看。

text=ZqhQzanResources