Linux 磁盘 I/O 性能诊断与存储故障排查
Linux 出现“系统很卡、CPU不高、数据库超时”时,根因可能位于应用、页缓存、文件系统、块设备、LVM、RAID、虚拟化存储、HBA、网络存储或物理磁盘。本文给出一套从症状到设备的分层诊断方法,避免只看到 iowait 就判断磁盘坏了。
压测工具会产生真实读写。
fio、丢弃、文件系统修复、RAID 重建和块设备写测试禁止在未知生产盘直接执行。
一、建立I/O路径
应用 read/write/fsync
↓
VFS与页缓存
↓
文件系统 ext4/xfs
↓
dm-crypt / LVM / multipath / mdraid
↓
块层队列与调度器
↓
驱动、HBA、虚拟磁盘或网络存储
↓
SSD/NVMe/HDD/存储阵列
故障定位要回答:
- 是读慢、写慢还是 fsync 慢;
- 是吞吐不足、IOPS 不足还是尾延迟升高;
- 是所有进程还是单个进程;
- 是单盘、单路径、单主机还是共享存储全局;
- 是持续问题还是定时任务触发;
- 是设备服务时间变慢,还是上层排队过多。
二、先采集基线
uptime
vmstat 1
mpstat -P ALL 1
pidstat -dru 1
iostat -xz 1
lsblk -o NAME,KNAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,ROTA,SCHED,MODEL,SERIAL
findmnt
df -hT
df -ih
同时保存内核日志:
journalctl -k --since '-2 hours'
dmesg -T | grep -Ei 'error|timeout|reset|abort|I/O|nvme|scsi|blk|ext4|xfs'
不要只截一秒数据。至少覆盖正常、异常和恢复阶段,并记录同一时间的业务吞吐。
三、正确理解iowait
wa 表示 CPU 空闲且至少有任务在等待 I/O 的时间比例。它不是磁盘利用率,也不能说明具体设备。CPU 很忙时,即使 I/O 很慢,iowait 也可能不高;系统只有少量 CPU 时,一条同步 I/O 也可能让比例看起来很高。
判断必须结合:
- 应用延迟和吞吐;
- 设备延迟和队列;
- 进程 I/O;
- 文件系统与内核错误;
- 存储后端指标。
四、阅读iostat关键字段
iostat -xz 1
不同版本字段略有差异,重点理解:
r/s、w/s:每秒请求数;rkB/s、wkB/s:吞吐;await:请求从提交到完成的平均时间,包含排队;r_await/w_await:读写延迟;aqu-sz:平均队列长度;%util:设备处理 I/O 的时间比例。
NVMe、阵列和并行设备即使 %util=100 仍可能继续处理更多 I/O;机械盘则更容易饱和。应以延迟、队列和业务 SLO 判断,而不是把 %util 当作统一红线。
五、定位产生I/O的进程
pidstat -d 1
iotop -oPa
cat /proc/<pid>/io
lsof -p <pid>
关注:
read_bytes/write_bytes:真正触发的存储 I/O;rchar/wchar:系统调用层处理字节,可能命中缓存;cancelled_write_bytes:写入后又被截断或删除;- 进程是否频繁 fsync;
- 是否由日志、备份、压缩、扫描、数据库 checkpoint 触发。
容器环境还要从宿主机、cgroup 和容器进程三个视角关联,避免只看容器内的虚拟设备。
六、页缓存与脏页
free -h
grep -E 'Dirty|Writeback|Cached|Buffers|MemAvailable' /proc/meminfo
vmstat 1
sysctl vm.dirty_ratio vm.dirty_background_ratio
sysctl vm.dirty_bytes vm.dirty_background_bytes
大量写入先进入页缓存,后台回写跟不上时,脏页持续增长;达到阈值后,应用可能被迫参与回写,出现周期性延迟尖峰。
治理顺序:
- 找到写入来源;
- 检查设备写入能力和延迟;
- 观察脏页增长与回落;
- 调整应用批量、日志和 checkpoint;
- 最后才根据内存和存储特性调整 dirty 参数。
不要在没有压测时盲目增大 dirty 阈值,它可能让更大的写入洪峰集中落盘。
七、同步写与fsync延迟
数据库和关键日志常依赖 fsync 保证持久化。吞吐看似正常,但单次落盘延迟升高就会放大事务提交时间。
可使用应用指标、数据库 WAL 指标、strace 短时采样或 eBPF 工具观察:
strace -ttT -p <pid> -e trace=fsync,fdatasync,read,write,pread64,pwrite64
strace 会带来开销,只应短时、针对单进程使用。更低干扰的环境可用 bcc/bpftrace 的 biolatency、biosnoop、fileslower 等工具。
八、文件系统检查
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
df -hT
df -ih
xfs_info <mountpoint>
tune2fs -l /dev/<device> 2>/dev/null
常见问题:
- 容量满或 inode 用尽;
- 文件删除但进程仍持有;
- 只读重挂载;
- ext4 journal 或 XFS 元数据错误;
- 大量小文件导致目录和元数据压力;
- 挂载参数不合适;
- 快照或 reflink 导致空间判断复杂。
查找已删除但仍占空间的文件:
lsof +L1
应通过安全地重载、轮转或重启对应进程释放句柄,不要直接操作 /proc/<pid>/fd 下未知描述符。
九、LVM、Device Mapper与快照
pvs
vgs
lvs -a -o +devices,segtype,data_percent,metadata_percent
dmsetup ls --tree
LVM thin pool 的 data 或 metadata 满都可能导致 I/O 失败。传统快照空间耗尽会失效;大量快照还会增加写放大。必须对 thin pool 数据、元数据、快照增长和自动扩容分别告警。
十、软件RAID
cat /proc/mdstat
mdadm --detail /dev/mdX
RAID 降级后仍可服务不代表安全。重建期间负载、温度和读取压力升高,另一块老盘可能继续失败。更换前核对序列号和槽位,重建时观察速度、错误和业务延迟。
RAID 不是备份,控制器缓存也必须有断电保护和可监控的电池/电容状态。
十一、NVMe与SSD健康
nvme list
nvme smart-log /dev/nvme0
smartctl -x /dev/nvme0
重点包括:
- critical warning;
- media/data integrity errors;
- available spare;
- percentage used;
- unsafe shutdowns;
- temperature;
- error log;
- 固件和 PCIe 链路状态。
SSD 延迟也可能因温度降速、垃圾回收、SLC 缓存耗尽、写放大或固件问题突然升高。健康百分比不是唯一判据。
十二、SATA/SAS/HDD与HBA
smartctl -x /dev/sdX
lsscsi -g
关注重新分配扇区、待处理扇区、不可校正错误、CRC、命令超时、介质和非介质错误。CRC 增长可能来自线缆、背板或 HBA,而非盘片。
内核出现 reset、abort、link down、I/O error 时要保存完整时间线,并关联控制器日志、阵列事件和机房操作。
十三、Multipath与SAN
multipath -ll
multipathd show paths
multipathd show maps
检查路径状态、优先级、策略和队列。queue_if_no_path 在所有路径丢失时可能让应用无限挂起;是否启用要由业务超时与恢复策略决定。
SAN 问题需要同时查看主机 HBA、交换机端口、阵列前端口、LUN 和存储池。单看 Linux 设备无法发现后端热点或控制器故障。
十四、NFS与分布式文件系统
nfsstat -m
nfsiostat 1
mountstats
网络文件系统的“磁盘慢”可能是 DNS、网络丢包、服务端负载、锁、挂载参数或元数据热点。检查请求重传、RTT、执行时间以及服务端磁盘,避免只在客户端调块设备参数。
十五、块层调度器与队列
cat /sys/block/<device>/queue/scheduler
cat /sys/block/<device>/queue/nr_requests
cat /sys/block/<device>/queue/read_ahead_kb
调度器选择与设备类型、虚拟化层和工作负载相关。数据库随机 I/O、大文件顺序读、桌面交互和共享阵列的最佳设置不同。调整前记录延迟分布和吞吐,调整后用真实业务回放验证。
十六、安全使用fio
只在独立测试文件或明确的测试盘上运行:
fio --name=randread --filename=/safe-test-path/fio.test \
--size=2G --rw=randread --bs=4k --iodepth=32 \
--ioengine=libaio --direct=1 --runtime=60 --time_based \
--group_reporting
生产验证要区分:
- 随机/顺序;
- 读写比例;
- 块大小;
- 队列深度和并发作业;
- buffered/direct;
- 平均延迟和 P95/P99/P999;
- 是否命中阵列缓存。
不要用超高队列深度制造漂亮 IOPS,却忽略业务真实尾延迟。
十七、常见故障处置
磁盘空间满
检查文件、inode、已删除句柄、日志、容器层、快照和数据库 WAL。先阻止继续增长,再安全释放或扩容。不要对数据库目录直接删除未知文件。
设备延迟突增
保存 iostat、进程 I/O、内核日志和后端存储指标;确认是否故障盘、路径切换、重建、备份或批任务;必要时限流非关键任务,避免重启丢失现场。
文件系统只读
读取内核错误并保护数据;确认底层设备是否仍稳定;在维护窗口卸载并按文件系统官方流程检查。在线强制修复可能扩大损坏。
云盘性能不足
核对规格的 IOPS、吞吐、突发积分和实例带宽上限;监控节流;区分本地系统队列与云平台限制。扩盘不一定自动提高文件系统和逻辑卷容量,也不一定立刻提升性能。
十八、监控清单
- 容量、inode、增长率和已删除句柄;
- 吞吐、IOPS、队列和读写延迟分位数;
- fsync/数据库提交延迟;
- iowait、阻塞任务和进程 I/O;
- 脏页、回写和内存压力;
- 文件系统错误和只读事件;
- RAID、Multipath、SAN/NFS 路径;
- SMART/NVMe 健康、温度和介质错误;
- 云盘节流或阵列缓存状态;
- 备份、快照和重建对业务的影响。
十九、结语
I/O 排障的关键不是记住某个阈值,而是把应用请求沿数据路径逐层拆开,分清设备服务慢、上层排队、缓存回写和后端限流。先保存证据并保护数据,再降低负载或切换路径,最后通过真实工作负载验证治理效果。
参考资料
- Linux kernel block documentation:https://docs.kernel.org/block/
- fio Documentation:https://fio.readthedocs.io/
- smartmontools:https://www.smartmontools.org/