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

vmstat 中 bi/bo 持续高位说明什么
这表示内核正在频繁进行块设备的读(bi)和写(bo)操作,但不等于有用户态进程在直接做大量 IO。常见于 page cache 回写、swap 活动、ext4/jbd2 日志提交、或内存回收触发的脏页刷盘。此时 top 或 htop 看不到明显 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/vmstat中pgpgout增速远高于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。










