大量脏页但 iostat 看不出哪个盘特别忙的匿名页/缓存排查

11次阅读

脏页积但iostat无磁盘热点,主因是swap、tmpfs或共享匿名映射产生的脏页不经过块设备I/O路径;需查pswpout、/proc/swaps、tmpfs使用量及mmap(MAP_ANONYMOUS|MAP_SHAred)进程。

大量脏页但 iostat 看不出哪个盘特别忙的匿名页/缓存排查

脏页堆积但 iostat 无明显磁盘热点,先确认脏页来源类型

linuxdirty_pages 不一定都来自文件系统写回——匿名页(如进程堆、mmap 私有匿名区)的换出(swap)也会产生脏页,但这类页不走 pdflushwriteback 路径,不会触发块设备写请求,因此 iostat 看不到对应磁盘 activity。此时 /proc/meminfo 中的 Dirty:Writeback: 可能偏高,但 pgpgout(每秒换出页数)和 pswpin/pswpout(swap in/out 次数)才是关键线索。

  • 运行 grep -E "Dirty|Writeback|pgpgout|pswpin|pswpout" /proc/vmstat,若 pswpout 显著上升而 pgpgout 增长平缓,基本可断定是 swap 引起的脏页堆积
  • 检查 /proc/swaps 是否启用 swapfile 或 swap partition;用 swapon --show=NAME,TYPE,SIZE,USED,PRI 确认活跃 swap 设备
  • 注意:即使 swapon -s 显示 swap 已关闭,内核仍可能因 vm.swappiness=100 或内存压力在 tmpfs(如 /dev/shm)上触发匿名页回收,这部分页会标记为 dirty 但不落地到磁盘

排查 tmpfs 和 shm 匿名页污染

tmpfs 是基于内存的文件系统,其内容本质是匿名页,且默认可被 swap。当应用往 /dev/shm 或自挂载的 tmpfs 写入大量数据(如数据库 shared memory segment、大 buffer mmap),这些页一旦变 dirty,就计入 Dirty: 统计,但不会触发块设备 I/O——因为没磁盘后端

  • df -t tmpfs 查看所有 tmpfs 挂载点使用量,重点关注 /dev/shm/run/sys/fs/cgroup 下的子挂载
  • 对可疑挂载点执行 find /dev/shm -type f -ls | sort -k7nr | head -10,找大文件或已删除但未释放的“幽灵文件”(lsof +L1 可辅助定位)
  • 临时禁用 tmpfs swap 行为:挂载时加 noexec,nosuid,nodev,mode=1777,size=2G,mpol=bind:0 并设 vm.mmap_min_addr=65536 减少 mmap 分配风险;长期方案需控制应用内存使用模式

确认是否 mmap(MAP_ANONYMOUS|MAP_SHARED) 导致脏页无法回收

共享匿名映射(mmap(..., MAP_ANONYMOUS|MAP_SHARED))产生的页,在 fork 后被子进程修改时会触发写时复制(COW),但若父/子均未调用 msync(MS_SYNC)munmap,这些页会持续处于 dirty 状态,且不归属任何文件,无法通过 syncecho 3 > /proc/sys/vm/drop_caches 清理。

  • cat /proc/[pid]/maps | grep -E "anon|shared" | awk '{print $5,$6}' | sort | uniq -c | sort -nr 扫描各进程的匿名共享映射大小
  • 结合 pstack [pid]lsof -p [pid] | grep mem 判断是否为数据库(postgresql shared memory)、jvm-XX:+UseSHM)、或自定义 IPC 使用了该模式
  • 这类页的生命周期由进程控制:只有进程退出、显式 munmap 或触发 OOM killer 才会真正释放;echo 1 > /proc/sys/vm/compact_memory 对它们无效

为什么 iostat 看不出问题?关键在 writeback vs swap vs tmpfs 路径分离

iostat 统计的是 blk_mq_make_request 层面的块设备 I/O,只覆盖文件系统 writeback 和 swap device I/O。而 tmpfs 页面回收走的是 shrink_slabshrink_page_listtry_to_unmap 路径;匿名页 swap out 走的是 swap_writepagesubmit_bio,但如果 swap 是 file-backed(swapfile),且该文件本身在 ext4/xfs 上,I/O 会被归入对应 block device;但若 swap 是 LVM LV 或 zram,iostat -x 需指定对应设备名(如 zram0)才可见。

  • 运行 iostat -x 1 3 时务必加上 -d 参数并列出所有块设备:lsblk -d -o NAME,TYPE,SIZE,ROTA,MODEL,避免漏看 zram、loop、nvme ns
  • cat /proc/buddyinfocat /proc/pagetypeinfo 可辅助判断是否因内存碎片导致 direct reclaim 频繁,进而推高 dirty page 回收延迟
  • 最易忽略的一点:某些容器运行时(如 containerd + overlayfs)在 /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs 下创建的 tmpfs mount,其 dirty 页完全不可见于宿主机 iostat,必须进容器命名空间
text=ZqhQzanResources