vmstat bi/bo 极高但无明显 IO 密集进程的 page cache 回写压力排查

10次阅读

vmstat中bi/bo持续高位说明内核正频繁进行块设备读写,常见于page cache回写、swap活动、ext4/jbd2日志提交或内存回收刷盘,而非用户进程直接IO。

vmstat bi/bo 极高但无明显 IO 密集进程的 page cache 回写压力排查

vmstat 中 bi/bo 持续高位说明什么

这表示内核正在频繁进行块设备的读(bi)和写(bo)操作,但不等于有用户态进程在直接做大量 IO。常见于 page cache 回写、swap 活动、ext4/jbd2 日志提交、或内存回收触发的脏页刷盘。此时 tophtop 看不到明显 IO 进程,恰恰是因为压力来自内核路径而非用户进程的 read()/write() 系统调用。

确认是否为 dirty page 回写主导

检查当前脏页比例和回写参数:

$ grep -E 'Dirty|Writeback|Ratio' /proc/vmstat $ sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_expire_centisecs vm.dirty_writeback_centisecs

关键判断点:

  • vmstat 1 中若 bo 高而 bi 很低,大概率是回写(不是读缓存失效)
  • /proc/vmstatpgpgout 增速远高于 pgpgin,且 pgmajfault 无明显增长 → 排除 swap 活动
  • cat /proc/meminfo | grep -i dirty 显示 Dirty: 值长期接近 vm.dirty_ratio 的 70% 以上

定位回写源头:jbd2、kswapd、写缓冲区激增

运行以下命令交叉验证:

$ iostat -x 1 3    # 观察 %util 和 await,确认是否真卡在磁盘层

%util 不高但 bo 高,说明回写请求被合并/排队,尚未真正下发;若 await 同步飙升,则磁盘已成瓶颈。

进一步抓取内核线程行为:

$ pidstat -u 1 -p $(pgrep "^jbd2" | head -1)   # jbd2 是 ext4 日志线程,高 CPU 表明日志刷盘频繁

同时检查:

  • ps auxf | grep "kswapd|kcompactd" —— 若 kswapd CPU 占用高,可能是内存紧张触发的脏页+匿名页同步回收
  • echo 1 > /proc/sys/vm/block_dump(慎用,仅临时)+ dmesg -w 可看到具体哪个文件/设备在被回写,但会显著影响性能
  • perf record -e block:block_rq_issue -a sleep 10 && perf script 查看块请求来源(需 root)

常见被忽略的诱因和缓解动作

很多 case 其实和应用无关,而是内核参数或文件系统行为导致:

  • vm.dirty_expire_centisecs 设得过大(如默认 3000=30s),导致脏页积压后集中爆发回写 → 可尝试调小到 1500
  • 使用 noatime,nobarrier 挂载选项的 ext4 在某些内核版本下会加剧 jbd2 负载 → 改用 barrier=1 或升级内核
  • 容器环境里,overlayfs 上层写入会放大底层 dirty page 生成量,尤其搭配 tmpfs 作为 upperdir 时更隐蔽
  • 应用未显式 fsync(),但用了 O_SYNC/O_DSYNC 打开文件 → 每次 write 都触发 journal 提交,等效高频 jbd2 活动

最易被跳过的一步:确认是否启用了 systemd-journald 并将日志持久化到磁盘(Storage=persistent),它本身就会产生稳定的小块写入流,叠加 page cache 后容易推高 bo

text=ZqhQzanResources