适用于 Linux 服务延迟升高、请求卡顿或写入耗时波动,且怀疑块存储 I/O 的场景。命令基线为 Linux 5.4+、util-linux 2.36+、procps-ng 3.3+;iostat 与 pidstat 来自 sysstat 12.2+,属于可选工具。读取其他进程、cgroup 和完整内核日志通常需要 root。示例路径 /path/to/data 与单元 app.service 必须替换为实际值。先保留故障窗口,不要一开始就清缓存、调整写回参数或在线跑写压测。
1. 固定实际文件系统与设备链路
date -u
uname -r
findmnt -T /path/to/data -o TARGET,SOURCE,FSTYPE,OPTIONS
lsblk -o NAME,KNAME,TYPE,PKNAME,MAJ:MIN,FSTYPE,SIZE,MOUNTPOINT
df -hT /path/to/data
df -ih /path/to/data
先确认应用路径落在哪个挂载点。LVM、device-mapper、软件 RAID、虚拟磁盘和云盘会形成多层设备,挂载源不一定就是最终承载 I/O 的物理设备;容器中的 overlayfs 也不能直接代表宿主机下层存储。采集命令应在故障发生的挂载命名空间执行,并同时保留宿主机视角。
df -h 与 df -i 用于先排除空间或 inode 耗尽。它们不能证明设备延迟正常。
2. 同时观察任务等待、PSI 与块设备统计
vmstat 1 10
cat /proc/pressure/io
iostat -xz -y 1 10
vmstat 的 wa 是采样期间 CPU 处于 I/O wait 的比例,不是单次请求延迟;b 增加说明不可中断睡眠任务增多,但不能单独归因到某块盘。I/O PSI 的 some 表示至少有任务因 I/O 停顿,full 表示所有非空闲任务同时停顿,它能反映工作负载受影响程度,却不指出具体设备。
在 iostat 中重点看读写吞吐、IOPS、队列深度和 await 的连续变化。await 包含排队与设备服务时间;单看一次尖峰不足以定性。%util 在传统单队列设备上可辅助判断忙碌程度,但对 NVMe、多队列、RAID 与虚拟设备不能简单解释为“达到 100% 才饱和”。第一份自启动以来的累计报告容易稀释故障,因此示例用 -y 跳过它。
3. 把设备压力关联到进程或服务
pidstat -d -p ALL 1 10
systemctl show app.service -p MainPID -p ControlGroup
stat -fc %T /sys/fs/cgroup
CG=$(systemctl show app.service -p ControlGroup --value)
cat "/sys/fs/cgroup${CG}/io.stat"
sleep 10
cat "/sys/fs/cgroup${CG}/io.stat"
最后四条只适用于 cgroup v2;stat 输出应为 cgroup2fs,并且目标单元的 ControlGroup 必须非空。io.stat 是按设备主次设备号累计的字节数和操作数,应比较固定时间间隔内的增量,再用 lsblk 的 MAJ:MIN 映射设备,不能直接比较不同服务的累计总数。
pidstat 可能漏掉生命周期很短的进程。缓冲写入还可能先记在应用,稍后由内核写回线程落盘,所以“看到内核线程写盘”不等于根因在内核线程;应与应用请求量、批处理任务和 cgroup 增量对齐。
4. 检查脏页回写是否造成周期性停顿
grep -E '^(Dirty|Writeback|WritebackTmp|NFS_Unstable):' /proc/meminfo
sysctl vm.dirty_background_bytes vm.dirty_background_ratio \
vm.dirty_bytes vm.dirty_ratio \
vm.dirty_expire_centisecs vm.dirty_writeback_centisecs
普通 write(2) 往往先写入页缓存,真正的设备 I/O 稍后发生;达到脏页阈值后,应用自身也可能参与回写并出现延迟尖峰。应连续采样 Dirty、Writeback、设备队列与应用延迟,观察它们是否同步增长和回落。
dirty_bytes 非零时会取代对应的 ratio 口径;比例阈值还会随可用内存规模变化。不要仅凭一个峰值修改这些主机级参数,调整前需要核对同机工作负载和持久化语义,尤其是依赖 fsync、数据库 WAL 或日志落盘的服务。
5. 排除设备超时与文件系统错误
journalctl -k --since '-30 min' --no-pager -o short-iso \
| grep -Ei 'I/O error|blk_update_request|buffer i/o|reset|timeout|nvme|ext4-fs error|xfs.*(error|corrupt)|read-only file system'
findmnt -T /path/to/data -o TARGET,SOURCE,FSTYPE,OPTIONS
若出现设备 reset、超时、介质错误、文件系统损坏或只读重挂载,优先保留完整内核日志、设备映射和存储平台事件;不要继续用压测扩大故障。主动 fio 测试必须在隔离、可丢弃且明确指定的测试卷上进行,不能把生产文件或裸设备当作临时验证目标。
6. 按同一口径闭环
修复后在代表性但受控的负载窗口重复采集:应用端延迟与错误率、iostat -xz、I/O PSI、目标 cgroup 的 io.stat 增量,以及内核日志。闭环标准不是某个指标瞬时下降,而是原入口延迟恢复,设备队列与 await 不再持续增长,脏页能够稳定回落,且没有新增超时或文件系统错误。
若瓶颈来自突发并发,应优先限制无界并发、建立背压或错峰;若是写回波动,应结合持久化要求和内存预算调整写入节奏;若底层存储持续报错,则应转入设备或平台故障处置,而不是只调应用超时。