问题根源在于内核页回收引发的隐式IO,包括脏页回写、swap交换及LRU回收同步触发的IO,均不归属用户进程,故iotop不可见但vmstat的bi/bo会升高。

当 vmstat 显示 bi(块设备读入 KB/s)和 bo(块设备写出 KB/s)持续很高,但 top、htop 或 iotop -a 却找不到明显 IO 密集的用户进程时,问题往往不在“谁在读写磁盘”,而在于内核如何管理内存——特别是**页回收(page reclaim)过程中触发的隐式 IO**。
缓存页回写(dirty page writeback)是常见元凶
Linux 会把文件系统写操作先暂存在 page cache(干净缓存页可直接丢弃,脏页必须落盘)。当脏页积累过多(超过 vm.dirty_ratio)、或达到回写阈值(vm.dirty_background_ratio),内核会启动 pdflush 或 writeback 线程异步刷盘。这个过程不归属任何用户进程,iotop 默认不显示内核线程的 IO,但 vmstat 的 bo 会如实反映。
- 检查当前脏页压力:
cat /proc/vmstat | grep -E "nr_dirty|nr_writeback" - 查看回写参数:
sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_expire_centisecs vm.dirty_writeback_centisecs - 临时缓解:增大后台回写阈值(如
sysctl -w vm.dirty_background_ratio=10),但需配合应用写模式评估,避免突发 flush 拖垮响应
匿名页交换(swap in/out)也会推高 bi/bo
当物理内存不足,内核需将匿名页(如堆、栈)换出到 swap 设备时,bo 会上升;若后续又频繁换入(例如 Java 应用堆碎片化严重、或误配了过小的 swapiness),bi 也会同步升高。这类 IO 同样不绑定用户进程,iotop 不显示 swap IO。
- 确认是否发生交换:
grep -i "swapped" /proc/vmstat或观察vmstat 1中 si/so 列 - 检查 swap 使用:
swapon --show+free -h - 降低非必要交换倾向:
sysctl -w vm.swappiness=1(容器环境常设为 0,但需确保内存充足)
内存回收(reclaim)引发的间接 IO
即使没脏页也没 swap,内核在 LRU 链表扫描回收页时,若遇到未写回的脏缓存页,会**同步触发 writeback**;若遇到映射了文件但被修改过的页(如 mmap 写入),也可能阻塞回收路径并拉起 IO。这种情况在 vmstat 中体现为 bi/bo 波动,同时 pgmajfault 或 pgpgin/pgpgout 可能上升。
- 监控回收行为:
vmstat 1 5关注 re(回收页数)、pgmajfault(次缺页异常) - 分析内存压力源:
cat /proc/meminfo | grep -E "(MemAvailable|Active|Inactive|SwapCached)" - 用
perf record -e 'kmem:mm_page_reclaim' -a sleep 10定位回收热点(需 root)
排查建议:绕过进程视角,直查内核内存状态
不要只盯着 “哪个进程在 IO”,先回答:“内核为什么不得不 IO?”
- 运行
echo 1 > /proc/sys/vm/block_dump(谨慎!仅调试用),然后dmesg -T | tail -50查看内核级块设备访问来源(含 writeback、swap、buffered reads) - 用
slabtop观察shmem_inode_cache、ext4_inode_cache等是否异常膨胀(可能暗示 tmpfs 或大量小文件缓存) - 检查是否有大量
tmpfs使用(df -t tmpfs),其内容修改会走 page cache 脏页路径,但无对应用户进程 IO 统计










