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:专门为闪存设计,碎片化控制更好。但早期版本有稳定性问题。
常见的文件系统问题:
- 碎片化:文件分散存储,导致读写变慢。可以用
e2fsck -f检查ext4的碎片率。 - 日志过大:ext4的journal如果太大,会影响写性能。可以用
tune2fs -l查看journal大小。 - 挂载参数不当:比如没有开启
noatime,每次读文件都会更新访问时间,增加IO开销。
我曾经踩过一个坑:某款设备在OTA升级后,系统分区变成了只读。排查了半天,发现是文件系统在升级过程中损坏了,触发了ext4的错误处理机制。
从那以后,我每次做OTA升级,都会在升级脚本里加一段文件系统检查的代码。
避坑指南:千万不要在生产环境直接对挂载中的文件系统做fsck。我曾经这么干过一次,结果把用户数据搞丢了。正确的做法是:先卸载,或者用只读模式挂载,再做检查。
15.5 知识体系总览
下面这张图,是我自己总结的存储与IO调试知识体系。你可以把它当作一个检查清单:
这张图把IO调试分成了四个维度:IO Wait分析、iostat监控、fio压力测试、文件系统问题。实际排查时,我一般会按照这个顺序来:先用top/vmstat看IO Wait是否异常,然后用iostat定位具体磁盘,再用fio验证性能上限,最后检查文件系统配置。
嗯,存储与IO调试,说白了就是「慢」字背后藏着一堆学问。掌握了这些工具和方法,你就能在系统卡顿的时候,快速找到那个拖后腿的「元凶」。
公众号:蓝海资料掘金营,微信deep3321