15、存储与IO调试:iostat、fio、IO Wait分析、文件系统问题

存储和IO调试,说白了就是跟「慢」做斗争。

我做了这么多年Android系统,最怕的就是用户反馈「手机卡」。你排查CPU、内存、网络都没问题,最后发现是IO在拖后腿。这种问题最隐蔽,也最让人头疼。

今天我们就来聊聊,怎么用iostat、fio这些工具,把IO问题揪出来。

15.1 IO Wait:系统卡顿的隐形杀手

先问个问题:你知不知道CPU在等什么?

CPU大部分时间都在等IO。等磁盘读写完成,等网络数据到达。这个等待时间,在Linux里就叫IO Wait。

我遇到过一台设备,CPU利用率只有30%,但系统卡得不行。一看IO Wait,高达60%。说白了,CPU大部分时间都在「干等」磁盘。

IO Wait的本质:CPU有空闲,但进程被阻塞在IO上。这时候你加CPU、减负载都没用,得从IO层面下手。

怎么查IO Wait?很简单:

# 用top命令,看wa那一列
top -n 1 | grep "%Cpu"

# 或者用vmstat,看wa列
vmstat 1 5

我个人的习惯是,先看vmstat的wa列。如果持续超过30%,基本可以断定IO有问题。

小技巧:IO Wait高不一定就是磁盘慢。有时候是文件系统锁竞争,有时候是内存不足导致频繁swap。别急着下结论,多看看其他指标。

15.2 iostat:IO性能的显微镜

iostat是我最常用的IO分析工具。它能告诉你每个磁盘的读写速度、IOPS、平均响应时间。

基本用法:

# 每2秒输出一次,共输出5次
iostat -x 2 5

输出结果里,我最关注这几个字段:

字段 含义 正常范围
r/s 每秒读请求数 取决于设备,一般<1000
w/s 每秒写请求数 同上
r_await 读请求平均等待时间(ms) <10ms为优秀,<50ms可接受
w_await 写请求平均等待时间(ms) 同上
%util 磁盘利用率 <80%为正常

我曾经遇到一个案例:某款手机在安装应用时特别慢。用iostat一看,w_await高达200ms,%util接近100%。

嗯,问题很明显——磁盘写性能瓶颈。后来发现是UFS存储的垃圾回收策略有问题,导致写入延迟暴增。

注意:%util达到100%不一定就是磁盘满了。它表示磁盘在持续工作,但可能是在做内部维护(比如垃圾回收)。这时候要看r_await和w_await是否同步升高。

15.3 fio:给存储系统做压力测试

iostat只能看现状,但如果你想测试存储的极限性能,就得用fio。

fio是个强大的IO基准测试工具。你可以模拟各种读写场景:顺序读、随机写、混合读写等等。

我常用的测试命令:

# 测试随机读性能
fio --name=randread --ioengine=libaio --iodepth=64 --rw=randread \
    --bs=4k --size=1G --numjobs=1 --runtime=60 --time_based

# 测试随机写性能
fio --name=randwrite --ioengine=libaio --iodepth=64 --rw=randwrite \
    --bs=4k --size=1G --numjobs=1 --runtime=60 --time_based

# 测试混合读写(70%读,30%写)
fio --name=rwmix --ioengine=libaio --iodepth=64 --rw=randrw \
    --rwmixread=70 --bs=4k --size=1G --numjobs=1 --runtime=60 --time_based

输出结果里,重点看这几个指标:

  • IOPS:每秒IO操作数。随机读写场景下,这个指标最重要。
  • 带宽:每秒传输的数据量。顺序读写场景下,这个指标更重要。
  • 延迟:每次IO操作的响应时间。99分位延迟(99.00th percentile)尤其值得关注。

我记得有一次,客户反馈他们的设备在跑某个App时特别卡。我拿fio一测,发现随机读IOPS只有不到5000,而竞品能做到15000以上。

这就是典型的存储性能不足。后来换了更高规格的UFS芯片,问题就解决了。

建议:在项目早期就用fio跑一遍基准测试。把结果存下来,后面出问题了好对比。我每个项目都会建一个「性能基线」文档,里面就包含fio的测试结果。

15.4 文件系统问题:那些年我们踩过的坑

存储性能不光取决于硬件,文件系统也至关重要。Android上主要用ext4和f2fs。

我个人的经验是:

  • ext4:成熟稳定,但碎片化问题比较严重。尤其是长时间使用后,文件读写性能会下降。
  • f2fs:专门为闪存设计,碎片化控制更好。但早期版本有稳定性问题。

常见的文件系统问题:

  1. 碎片化:文件分散存储,导致读写变慢。可以用e2fsck -f检查ext4的碎片率。
  2. 日志过大:ext4的journal如果太大,会影响写性能。可以用tune2fs -l查看journal大小。
  3. 挂载参数不当:比如没有开启noatime,每次读文件都会更新访问时间,增加IO开销。

我曾经踩过一个坑:某款设备在OTA升级后,系统分区变成了只读。排查了半天,发现是文件系统在升级过程中损坏了,触发了ext4的错误处理机制。

从那以后,我每次做OTA升级,都会在升级脚本里加一段文件系统检查的代码。

避坑指南:千万不要在生产环境直接对挂载中的文件系统做fsck。我曾经这么干过一次,结果把用户数据搞丢了。正确的做法是:先卸载,或者用只读模式挂载,再做检查。

15.5 知识体系总览

下面这张图,是我自己总结的存储与IO调试知识体系。你可以把它当作一个检查清单:

存储与IO调试知识体系 IO性能问题 IO Wait分析 top/vmstat CPU等待占比 iostat监控 r/s, w/s r_await, %util fio压力测试 IOPS/带宽 延迟分布 文件系统问题 ext4 vs f2fs 碎片化/日志 从现象到根因,一步步定位IO瓶颈

这张图把IO调试分成了四个维度:IO Wait分析、iostat监控、fio压力测试、文件系统问题。实际排查时,我一般会按照这个顺序来:先用top/vmstat看IO Wait是否异常,然后用iostat定位具体磁盘,再用fio验证性能上限,最后检查文件系统配置。

嗯,存储与IO调试,说白了就是「慢」字背后藏着一堆学问。掌握了这些工具和方法,你就能在系统卡顿的时候,快速找到那个拖后腿的「元凶」。


公众号:蓝海资料掘金营,微信deep3321