Linux CPU iowait 高 & K8s + overlayfs 排查笔记
目录标题
- 📘 Linux CPU iowait 高 & K8s + overlayfs 排查笔记
- 🚑 iowait 高 · 现场速查表
- 🧨 K8s I/O 排雷设计清单(工程版)
- 0107补充
- 1️⃣ xfsaild 是干嘛的?
- 2️⃣ 有 xfsaild 代表什么?
- 3️⃣ 什么情况下 xfsaild 说明「有压力」?
- 4️⃣ 为什么 overlayfs 场景特别容易把 xfsaild 打满?
- 5️⃣ 如何证明:xfsaild 是不是“瓶颈点”?
- 6️⃣ 总结一句“能不能代表问题”
- 一句话结论(先记住)
- 1️⃣ overlayfs 在容器里「具体用在什么地方」?
- 2️⃣ 那 localpv / 本地挂载盘算不算 overlayfs?
- 3️⃣ ⚠️ 但为什么很多人“以为 localpv 也被 overlay 影响”?(重点)
- 4️⃣ 哪些「容器行为」最容易打爆 overlayfs(对你排障很重要)
- 5️⃣ 如何**明确区分:压力来自 overlayfs 还是 localpv?**
- 6️⃣ 给你一个可以直接写进分析报告的结论模板
📘 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 average | uptime / top | 运行队列 + D 状态队列平均 | < CPU 核心数 | > CPU 核心数 2x | |
| D 状态进程数 | `ps -eo pid,stat,comm | grep ’ D’` | 不可中断睡眠 | 0-少量 | > 10-20 或关键应用阻塞 |
| await | iostat -x | 每次 I/O 平均等待时间 | < 10ms | > 50ms 持续 | |
| aqu-sz | iostat -x 或 /sys/block/*/queue/ | I/O 队列深度 | < 1 | > 8-16 持续 | |
| %util | iostat -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 写放大链路
这份笔记已经涵盖了:
- 原理理解
- 指标解释
- 排查步骤(CPU → 进程 → block → fs → device)
- 命令实践
- 经验值参考
- 可直接用在事故分析的模板
- 图示辅助理解
好,那我给你一份 「一页纸 · 现场速查表」。
目标只有一个:事故现场 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-sz | I/O 排队长度 |
| %util | 设备是否被打满 |
经验阈值(重要)
| aqu-sz | 判断 |
|---|---|
| < 1 | 正常 |
| 1 ~ 4 | 可接受 |
| 4 ~ 8 | 开始拥堵 |
| 8 ~ 16 | 明显异常 ⚠️ |
| > 16 | I/O 雪崩前夜 ❌ |
👉 aqu-sz 高 = 上游写入模型压垮 block queue
🚫 常见误区
- 看到 await 高就说“磁盘慢”
👉 不一定
4️⃣ fs 层(K8s 核心杀点)
关键角色
- XFS →
xfsaild - ext4 →
jbd2
看什么
- 是否处于 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 Daqu-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 个坑
- ❌ iowait 高就扩 CPU
- ❌ load 高就说算力不足
- ❌ 先查应用、SQL
- ❌ 不看 aqu-sz
- ❌ 不理解 overlayfs 写放大
如果你愿意,下一步我可以再帮你做一件“更工程化”的事:
👉 把这套速查表升级成「设计规避清单」
(哪些场景不该用 overlayfs、DB 如何落盘、node 级别怎么拆)
你要 「排雷设计版」 还是 「事故复盘模板版」?
好,这一步已经是从“会排障”升级到“会设计”了。
下面这份是 《K8s + 容器 + overlayfs 的 I/O 排雷设计版》 ——目标只有一个:
让 iowait 事故“设计上就不可能发生”
🧨 K8s I/O 排雷设计清单(工程版)
一句话设计总原则(先记住)
overlayfs 只适合“读多写少、无状态”
数据库 / 高写入 = 必须绕开它
1️⃣ 应用 / 数据层设计(最重要)
❌ 禁止场景(高危)
| 场景 | 原因 |
|---|---|
| DB 数据目录在容器可写层 | copy-up + metadata 放大 |
| 大量小文件频繁写 | inode / dentry 爆炸 |
| fsync 频繁(数据库) | journal 压力极大 |
| WAL / redo 在 overlayfs | log 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 条铁律
- 数据目录 必须 volume
- WAL / redo 独立目录
- fsync 策略明确
- 容器 rootfs 只读
- 禁止 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_forceblk_mq_get_tagio_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:
- copy lower → upper
- 新建 inode
- 更新 dentry
- 更新 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/log | metadata 放大 |
rm -rf 容器目录 | unlink 风暴 |
| 应用自解压 | create / chmod / rename |
yum install / pip install | inode + 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 / 业务 / 日志)
更多推荐
所有评论(0)