脏页积压主因是vm.dirty_background_ratio过低导致回写过早且不畅,而非vm.dirty_ratio未达阈值;需同步调高background_ratio(15–25)、dirty_ratio(30–40),并缩短dirty_expire_centisecs(1000–1500)以均衡回写节奏。
为什么 vm.dirty_ratio 调高了,脏页还是积压?
因为内核不会等脏页涨到 vm.dirty_ratio 才开始回写——它更早就会触发异步回写,而触发阈值由 vm.dirty_background_ratio 控制。如果这个值太低(比如默认 10),系统会频繁唤醒 pdflush(或现代内核的 writeback 线程),但线程本身可能被 I/O 延迟卡住、或受限于设备吞吐,导致脏页“产速>写速”,越积越多。
常见错误现象:iostat -x 显示 %util 持续低于 30%,但 /proc/meminfo 中 Dirty: 和 Writeback: 居高不下,应用 write() 延迟升高。
-
vm.dirty_background_ratio建议调至 15–25(视内存总量而定),避免过早、过碎的回写打断业务 IO -
vm.dirty_ratio可同步上调至 30–40,为突发写留出缓冲空间,但别超过 50,否则sync()或内存回收时容易卡死 - 必须配对调整
vm.dirty_background_bytes和vm.dirty_bytes(二者与 *_ratio 互斥),否则 ratio 设置会被忽略
vm.dirty_expire_centisecs 设太长,脏页就“赖着不走”
这个参数决定脏页在内存里最多“躺”多久才必须被回写(单位是厘秒,即 1/100 秒)。默认 3000(30 秒),看似宽松,但在高吞吐写场景下,大量脏页会在 30 秒内反复被标记为“可回写”,却因 writeback 线程调度或磁盘队列阻塞迟迟没发出,最终全部挤在 expire 临界点前集中冲刷,造成 I/O 尖峰。
使用场景:SSD 或 NVMe 后端、日志型写入(如 Kafka broker、数据库 WAL)、容器环境共享宿主机 page cache。
- 把
vm.dirty_expire_centisecs从 3000 降到 1000–1500(10–15 秒),让回写节奏更均匀 - 注意:设太短(如
- 该值不影响已进入
Writeback:状态的页,只约束“脏了但还没排队”的页
为什么 iostat %util 看着不高,磁盘其实已经饱和?
%util 是基于设备忙闲时间统计的,对 NVMe 或多队列 SCSI 设备意义很弱——它只看单个请求队列是否 busy,而现代存储能并行处理数百请求。实际瓶颈常在文件系统层(如 ext4 journal 锁)、块层调度器(cfq 已弃用,但 mq-deadline 的 deep queue 行为难预测),或 RAID 卡缓存策略上。