目录标题


📘 Linux CPU iowait 高 & K8s + overlayfs 排查笔记


1️⃣ 基础原理

CPU iowait 本质

  • 定义:CPU 空闲状态下,存在未完成 I/O 请求的等待时间。

  • 关键点

    • CPU 并未在忙计算,只是在 idle 状态等待 I/O 返回。
    • 高 iowait ≠ CPU 繁忙
    • iowait 高往往伴随 进程大量 D 状态

load average 与 iowait关系

  • load = R 状态(可运行) + D 状态(不可中断睡眠)
  • D 状态堆积 → load 升高 → iowait 升高
  • ⚠️ 误区:load 高 ≠ CPU 算力不足

2️⃣ K8s + overlayfs 场景下 iowait 高典型链条

上游写请求 (应用 / 数据库)
        ↓
overlayfs copy-up
        ↓
文件系统元数据 / 日志写 (XFS: xfsaild, ext4: jbd2)
        ↓
block 层队列堆积 (aqu-sz 高)
        ↓
CPU iowait ↑
        ↓
进程 D 状态增加
        ↓
kubelet 超时
        ↓
Pod 容器阻塞 / 服务不可用

关键理解

  • xfsaild / jbd2:负责 fs 日志与元数据提交,是“写路径后台线程”。

    • 高 iowait + D 状态时,它们通常在阻塞,导致整个文件系统写路径阻塞。
  • aqu-sz:block 层 I/O 队列深度。

    • 高 aqu-sz = 上游写入模型压垮设备队列,而不一定是磁盘慢。

3️⃣ 指标解读

指标来源含义正常值危险值
iowait/proc/stat / node_exporter node_cpu_seconds_total{mode="iowait"}CPU 等待 I/O 的百分比< 5%> 20% 持续时间长
load averageuptime / top运行队列 + D 状态队列平均< CPU 核心数> CPU 核心数 2x
D 状态进程数`ps -eo pid,stat,commgrep ’ D’`不可中断睡眠0-少量> 10-20 或关键应用阻塞
awaitiostat -x每次 I/O 平均等待时间< 10ms> 50ms 持续
aqu-sziostat -x/sys/block/*/queue/I/O 队列深度< 1> 8-16 持续
%utiliostat -x设备繁忙度< 50%> 80%

4️⃣ 排查路径(实战版)

0️⃣ CPU 层

  • 确认 CPU 是否真忙
top
mpstat -P ALL 1
  • 判断依据:iowait 高,user/system 不高 → CPU 无罪

1️⃣ 进程层

  • 确认 D 状态进程
ps -eo pid,stat,comm | grep ' D'
  • 结论:大量 D 状态 → I/O 阻塞已经发生

2️⃣ block 层

  • 查看设备 I/O 延迟和队列
iostat -x 1
cat /sys/block/dm-*/queue/nr_requests
  • 关注字段

    • await:单次 I/O 平均等待时间
    • aqu-sz:队列深度
    • %util:设备利用率

3️⃣ 文件系统层(overlayfs + XFS / ext4)

  • 识别元数据 / 日志写压力
ps -eo pid,stat,comm | egrep 'xfsaild|jbd2'
  • 特征

    • 队列阻塞
    • 小文件写入放大
    • overlayfs copy-up
    • fs metadata/journal 写延迟

4️⃣ device 层(最后一刀)

  • 检查存储设备健康及异常
dmesg | egrep -i 'error|timeout|reset'
smartctl -a /dev/sdX
multipath -ll
  • 判断依据

    • 设备是否出现物理问题
    • RAID / SAN / NVMe 异常

5️⃣ 实战口诀

iowait 高 + D 多 + user/system 不高
→ 跳过 CPU / 应用,直接沿 block → fs → device 查


6️⃣ 事故报告模板

本次 CPU iowait 升高并非 CPU 算力瓶颈,而是由于容器环境下 overlayfs 叠加 XFS 文件系统,在高写入场景中触发元数据与日志写放大,导致 block I/O 阻塞。进程大量进入 D 状态,进一步推高 iowait 与 load average,最终引发 kubelet 超时与 Pod 不可用。


7️⃣ 可视化图示

  • 图示文件:/mnt/data/A_digital_diagram_illustrates_the_impact_of_overla.png
  • 描述:展示应用写请求 → overlayfs → XFS/jbd2 → block queue → CPU iowait → D 状态 → Pod 阻塞
  • 功能:帮助快速理解 K8s + overlayfs 场景下 I/O 写放大链路

这份笔记已经涵盖了:

  1. 原理理解
  2. 指标解释
  3. 排查步骤(CPU → 进程 → block → fs → device)
  4. 命令实践
  5. 经验值参考
  6. 可直接用在事故分析的模板
  7. 图示辅助理解

好,那我给你一份 「一页纸 · 现场速查表」
目标只有一个:事故现场 3 分钟内定性,不走弯路

你可以直接存成笔记 / Wiki / 事故手册。


🚑 iowait 高 · 现场速查表

(K8s + 容器 + overlayfs 专用)


0️⃣ 一眼判断(先别敲命令)

看到监控如果是:

  • iowait ↑
  • load ↑
  • user + system 不高

👉 结论先下:CPU 无罪,直接查 I/O


1️⃣ CPU 层(只看 30 秒)

看什么

  • iowait 是否明显高
  • us / sy 是否不高

命令

top
mpstat -P ALL 1

结论

  • iowait 高 + us/sy 低
    不要再看 CPU

🚫 常见误区

  • 调 CPU limit / request
  • 扩容 CPU
    👉 完全无效

2️⃣ 进程层(铁证)

看什么

  • 大量进程 STAT = D

  • 是否包含:

    • 数据库
    • runc / containerd
    • kubelet
    • curl / bash

命令

ps -eo pid,stat,comm | grep ' D'

结论

  • D 状态多
    I/O 已经 block,是“因”,不是果

3️⃣ block 层(分水岭)

核心命令

iostat -x 1

只盯 3 个指标

指标看什么
await单次 I/O 等多久
aqu-szI/O 排队长度
%util设备是否被打满

经验阈值(重要)

aqu-sz判断
< 1正常
1 ~ 4可接受
4 ~ 8开始拥堵
8 ~ 16明显异常 ⚠️
> 16I/O 雪崩前夜 ❌

👉 aqu-sz 高 = 上游写入模型压垮 block queue

🚫 常见误区

  • 看到 await 高就说“磁盘慢”
    👉 不一定

4️⃣ fs 层(K8s 核心杀点)

关键角色

  • XFSxfsaild
  • ext4jbd2

看什么

  • 是否处于 D 状态

命令

ps -eo pid,stat,comm | egrep 'xfsaild|jbd2'

一旦命中,直接下结论

overlayfs + fs 元数据 / 日志写被卡住

典型伴随:

  • df 没满
  • 系统却“写不动”
  • 所有容器一起卡

🚫 常见误区

  • 查 SQL
  • 查应用 Bug
    👉 都不是第一现场

5️⃣ device 层(最后才看)

什么时候看?

  • fs 层确认有问题
  • block 层已经排队
  • 才看 device

命令

dmesg | egrep -i 'error|timeout|reset'
multipath -ll
smartctl -a /dev/sdX

关注点

  • timeout / reset
  • SAN / 云盘 latency 抖动
  • RAID 重构

6️⃣ K8s + overlayfs 专属「断案公式」

只要同时满足三点:

  • iowait ↑
  • xfsaild / jbd2 D
  • aqu-sz ↑

👉 99% 不是盘坏,是写放大


7️⃣ 一句话专家级总结(背下来)

CPU iowait 升高并非 CPU 算力瓶颈,而是容器环境下 overlayfs 叠加文件系统元数据与日志写放大,导致 block 层队列堆积(aqu-sz 升高),I/O 请求无法及时完成,引发进程大量进入 D 状态并最终影响 kubelet 与 Pod 稳定性。


8️⃣ 排查顺序(千万别反)

CPU(确认无罪)
  ↓
进程 D 状态
  ↓
block queue(aqu-sz)
  ↓
fs(xfsaild / jbd2)
  ↓
device(最后)

9️⃣ 最容易踩的 5 个坑

  1. ❌ iowait 高就扩 CPU
  2. ❌ load 高就说算力不足
  3. ❌ 先查应用、SQL
  4. ❌ 不看 aqu-sz
  5. ❌ 不理解 overlayfs 写放大

如果你愿意,下一步我可以再帮你做一件“更工程化”的事

👉 把这套速查表升级成「设计规避清单」
(哪些场景不该用 overlayfs、DB 如何落盘、node 级别怎么拆)

你要 「排雷设计版」 还是 「事故复盘模板版」

好,这一步已经是从“会排障”升级到“会设计”了
下面这份是 《K8s + 容器 + overlayfs 的 I/O 排雷设计版》 ——目标只有一个:

让 iowait 事故“设计上就不可能发生”


🧨 K8s I/O 排雷设计清单(工程版)


一句话设计总原则(先记住)

overlayfs 只适合“读多写少、无状态”
数据库 / 高写入 = 必须绕开它


1️⃣ 应用 / 数据层设计(最重要)

❌ 禁止场景(高危)

场景原因
DB 数据目录在容器可写层copy-up + metadata 放大
大量小文件频繁写inode / dentry 爆炸
fsync 频繁(数据库)journal 压力极大
WAL / redo 在 overlayfslog force 雪崩

👉 这些场景 = 必出 iowait


✅ 正确做法(必须)

数据目录直挂 volume(绕开 overlayfs)
volumeMounts:
- name: data
  mountPath: /var/lib/postgresql

底层推荐:

  • local SSD
  • 独立云盘
  • 直通 NVMe

✔️ 目标:数据写入不经过 overlayfs


2️⃣ 容器文件系统设计

overlayfs 该干什么?

✅ 适合:

  • 程序二进制
  • 配置文件
  • 只读依赖

❌ 不适合:

  • DB data
  • 日志
  • 临时文件高频写

日志设计(非常关键)

❌ 高危
  • 容器内写 /var/log
  • 应用自己 rotate
✅ 正确
  • stdout / stderr
  • Sidecar / daemon 收集

👉 避免 log 文件的小写风暴


3️⃣ K8s 存储选型排雷

local vs 网络盘

场景建议
DB / 高写local SSD / 本地 NVMe
一般有状态独立云盘
临时缓存emptyDir + medium: Memory

emptyDir 的坑

emptyDir:
  medium: ""
  • 默认 = 走 node fs(overlayfs 下)
  • 高频写 → 仍可能压 fs

👉 高频临时写建议:

emptyDir:
  medium: Memory

4️⃣ Node 级别文件系统设计

XFS 推荐参数(生产)

mkfs.xfs -m reflink=0 -n ftype=1
  • ftype=1:overlayfs 必须
  • reflink=0:减少 copy-on-write

mount 参数建议

noatime,nodiratime,logbufs=8,logbsize=256k

目的:

  • 减少 metadata 写
  • 减轻 xfsaild 压力

5️⃣ block 层设计(容易被忽略)

队列深度要配得上写入模型

cat /sys/block/nvme0n1/queue/nr_requests

经验值:

  • NVMe:128 ~ 1024
  • 云盘:按厂商建议

🚫 队列太小
→ aqu-sz 很快堆满
→ iowait 爆炸


6️⃣ 数据库容器化专项排雷

必须满足的 5 条铁律

  1. 数据目录 必须 volume
  2. WAL / redo 独立目录
  3. fsync 策略明确
  4. 容器 rootfs 只读
  5. 禁止 DB 写 overlayfs

7️⃣ 监控 & 预警设计(提前拦截)

必须监控的 3 个指标

指标告警
CPU iowait> 20%
aqu-sz> 8
D 状态进程数持续增长

👉 aqu-sz 是“雪崩前指标”


8️⃣ 一句话设计总结(终极版)

任何需要稳定写入延迟的业务,都不应依赖 overlayfs 的可写层。
在 K8s 中,overlayfs 是“运行时层”,而不是“数据层”。


9️⃣ 你现在已经具备的能力

到这里你已经能做到:

  • 看 iowait 不再看 CPU
  • 看 aqu-sz 就能预判雪崩
  • 一眼识别 overlayfs 写放大
  • 设计上规避事故

这已经是 SRE / 内核级排障思维,不是普通运维了。


如果你愿意,最后我可以帮你做一件“压轴”的事

0107补充

一句话先给结论:

看到 xfsaild 进程 ≠ 一定有问题
xfsaild 持续活跃 / D态 / CPU异常 / wchan卡在 log 或 IO 上,基本就能说明:XFS 的元数据或日志写入存在压力或阻塞。

下面我分 “它是什么” → “它忙说明什么” → “哪些状态才算异常” → “如何和你现在的 overlayfs / NVMe 场景对应” 给你讲清楚。


1️⃣ xfsaild 是干嘛的?

xfsaild = XFS AIL daemon

  • AIL(Active Item List)
    XFS 中已修改但还没真正落盘的元数据

  • xfsaild 的职责:

    • 把这些脏的元数据
    • 按顺序刷入 XFS journal(log)
    • 再由 log flush 到磁盘

📌 本质一句话:

xfsaild = XFS 的“元数据清算 / 日志提交线程”


2️⃣ 有 xfsaild 代表什么?

✔ 正常含义(最常见)

系统在使用 XFS 文件系统

只要挂了 XFS:

mount | grep xfs

就一定能看到:

xfsaild/<dev>

👉 “存在”本身完全正常


3️⃣ 什么情况下 xfsaild 说明「有压力」?

关键不在 有没有,而在 它在干什么状态

🔥 关键观察点

ps -eo pid,stat,comm,wchan:20 | grep xfsaild
① D 状态(最危险)
STAT = D

含义:

xfsaild 在等 IO 完成,被磁盘/队列卡住

常见 wchan:

  • xfs_log_force
  • blk_mq_get_tag
  • io_schedule

📌 结论:

XFS journal / metadata 写被底层 block 层堵死


② R 状态 + CPU 高
STAT = R
%CPU 持续 > 10%~20%

说明:

  • 元数据修改量非常大
  • xfsaild 一直在扫描、提交 AIL
  • 小文件 / 高频 create/unlink / rename

📌 典型场景:

  • 容器 overlayfs
  • 日志系统
  • 编译 / unpack / rpm / pip install

③ xfsaild 数量异常多
ps -ef | grep xfsaild

你会看到类似:

xfsaild/sda
xfsaild/nvme0n1

👉 每个 XFS 设备一个 xfsaild

  • 多个没问题
  • 某一个特别忙 / 卡住 → 问题盘

4️⃣ 为什么 overlayfs 场景特别容易把 xfsaild 打满?

这点和你之前 NVMe 延迟的判断是强相关的

overlayfs 的“暗伤”

① copy-up 写放大
  • 容器写一个小文件

  • overlayfs:

    1. copy lower → upper
    2. 新建 inode
    3. 更新 dentry
    4. 更新 xattr

👉 一次写 = N 次元数据修改


② 小 IO ≠ 低压力

你之前说过:

「我看 IO 也不高啊」

这里就是典型误区:

指标看起来实际
吞吐 MB/s很低
IOPS不高
元数据操作极高
journal 写高频 sync

👉 xfsaild 会被“无形压力”压死


5️⃣ 如何证明:xfsaild 是不是“瓶颈点”?

必做三连

① 看 D 状态
ps -eo pid,stat,comm,wchan:20 | grep xfsaild

出现:

D  xfsaild/nvme0n1  xfs_log_force

铁证


② 看 IO 等待
iostat -x 1

如果:

  • %util
  • await
  • r/s w/s 不高

典型 metadata/journal 压力


③ 看 overlayfs 写行为
perf top -p $(pidof xfsaild)

若看到:

  • xfs_log_*
  • xfs_trans_*

元数据提交风暴


6️⃣ 总结一句“能不能代表问题”

你可以直接这样下结论(报告级别)👇:

系统中存在 xfsaild 为正常现象,
但在 overlayfs 容器写入场景下,xfsaild 持续处于 D 状态 / 高 CPU
表明 XFS 元数据及日志写入存在明显压力
即使业务 IO 吞吐不高,也会导致 NVMe 设备长时间繁忙和写延迟放大。


如果你愿意,下一步我可以帮你做三件事之一(你选):

1️⃣ 根据你当前 ps / iostat 输出,直接给定性结论
2️⃣ 写一个“xfsaild 异常判定规则”脚本(自动告警)
3️⃣ 给出 overlayfs + XFS 的参数/架构级优化建议(可落地)

这个问题问得非常关键,而且你现在的理解方向基本是对的 👍
我直接给你一个结论先行 + 细节拆解的答案。


一句话结论(先记住)

overlayfs 只作用在「容器镜像层 + 容器可写层」
你用的 localpv(hostPath / 本地盘直挂)本身 ≠ overlayfs,不会走 copy-up

但是 ⚠️ 有两个很容易被忽略的“交叉点”,这也是很多线上问题的根源。

下面我逐层给你拆清楚。


1️⃣ overlayfs 在容器里「具体用在什么地方」?

① 容器 rootfs(100% 是 overlayfs)

每一个容器都有:

lowerdir = 镜像只读层
upperdir = 容器可写层
merged   = 容器看到的 /

你可以在宿主机看到类似:

mount | grep overlay
overlay on /var/lib/containerd/.../rootfs type overlay

👉 容器内写 /etc/var/lib/tmp/usr
👉 全部命中 overlayfs


② 哪些「容器路径」一定走 overlayfs?

容器内这些路径 默认都是 overlayfs

路径是否 overlayfs
/etc
/var/log
/var/lib/*
/tmp
/root

📌 只要你没显式挂 volume,就一定是 overlayfs。


2️⃣ 那 localpv / 本地挂载盘算不算 overlayfs?

✅ 正确答案:不算

典型 localpv 挂载:

volumeMounts:
- mountPath: /data
  name: localpv

宿主机:

/dev/nvme0n1  -> /mnt/localpv -> /data (in container)

此时:

  • /data 直接是 XFS / ext4
  • 不经过 overlayfs
  • 没有 copy-up
  • 行为 = 裸文件系统

👉 你理解是完全正确的


3️⃣ ⚠️ 但为什么很多人“以为 localpv 也被 overlay 影响”?(重点)

这里有 2 个非常隐蔽的坑


❗坑 1:程序“以为”自己在写数据盘,其实写在 rootfs

非常常见:

配置写 /data
程序实际写 /var/lib/app/data

或者:

日志目录没挂 volume
日志疯狂写 /var/log/app.log

📌 结果:

  • 数据没落到 localpv
  • 全在 overlayfs
  • xfsaild 被打爆

👉 这是线上最常见的 overlayfs 元数据风暴来源

快速验证

进容器执行:

df -T

如果看到:

overlay  overlay  /
xfs      xfs      /data

再:

findmnt /data
findmnt /

❗坑 2:localpv 目录「初始化阶段」发生 overlay copy-up

典型场景:

volumeMounts:
- mountPath: /var/lib/mysql
  name: localpv

但:

  • 镜像里 已经有 /var/lib/mysql

  • 容器启动前会发生:

    • 目录存在性检查
    • 权限修正
    • SELinux label
    • 甚至初始化文件

📌 这些动作发生在 volume 挂载之前

👉 结果:

  • 触发 overlayfs copy-up
  • 产生大量 inode / dentry / xattr
  • xfsaild 有压力,但你“明明用了 localpv”

4️⃣ 哪些「容器行为」最容易打爆 overlayfs(对你排障很重要)

🔥 高危行为清单

行为原因
小文件日志写 /var/logmetadata 放大
rm -rf 容器目录unlink 风暴
应用自解压create / chmod / rename
yum install / pip installinode + xattr
init 容器拷贝文件copy-up

5️⃣ 如何明确区分:压力来自 overlayfs 还是 localpv?

三步定因法(推荐你现在就用)

① overlayfs 是否忙
mount | grep overlay
ps -eo pid,stat,comm,wchan:20 | grep xfsaild

② 看 IO 来自哪里(非常关键)
iostat -x 1
  • 对比:
  • overlay 上层盘
  • localpv 对应 NVMe

📌 overlayfs 盘忙,localpv 盘不忙 → overlay 问题


③ 查容器真实写入路径
lsof +D /var/lib/containerd | wc -l
lsof +D /mnt/localpv | wc -l

谁多,压力就在哪。


6️⃣ 给你一个可以直接写进分析报告的结论模板

你可以直接用这段 👇

经核查,overlayfs 仅用于容器镜像层及容器可写层(rootfs),
localpv 本地盘为直挂 XFS 文件系统,不经过 overlayfs,不存在 copy-up 行为。
但若业务日志、临时文件或初始化操作发生在未挂载 volume 的路径(如 /var/log、/tmp、/var/lib),
仍会触发 overlayfs 元数据写放大,导致 XFS journal 压力及 xfsaild 活跃。


如果你愿意,下一步我可以帮你 “精准到 Pod 级别”

  • 🔍 哪个 Pod 在写 overlayfs
  • 🔍 写的是 日志 / tmp / 配置 / 初始化文件
  • 🔧 给你一份 容器 + localpv 最佳挂载路径规范

你只要告诉我:
👉 你现在怀疑的是哪类 Pod(DB / MQ / 业务 / 日志)

更多推荐