4. 常见瓶颈:磁盘利用率100%、IO等待过高、单盘性能瓶颈、文件系统锁竞争
磁盘IO出问题,说白了就那几类症状。我干了十几年运维,见过的IO故障少说也有上百起,最后都能归到这四个坑里。今天咱们一个一个掰开揉碎了讲。
4.1 磁盘利用率100%:是真是假?
很多人一看到iostat里%util飙到100%,就慌了。其实这里有个常见的误解。
关键点:%util 100% 不代表磁盘已经满负荷运转。它只表示在采样周期内,磁盘有100%的时间都在处理请求——哪怕只处理了一个很小的请求。
举个例子。我在项目中遇到过一台数据库服务器,%util长期100%,但吞吐量才不到50MB/s。查了半天,发现是上层应用在疯狂做4KB的随机写。磁盘其实没吃饱,但被这些小IO请求塞满了队列。
怎么判断真假?我个人的习惯是看两个指标:
- 平均IO大小(
avgrq-sz):如果小于16KB,说明IO以小请求为主,利用率虚高。 - IO等待队列长度(
avgqu-sz):如果队列长度超过磁盘并发能力的2倍,才是真正的瓶颈。
| 场景 | %util | avgrq-sz | avgqu-sz | 真实结论 |
|---|---|---|---|---|
| 小IO风暴 | 100% | 4-8KB | 低(<2) | 利用率虚高,优化应用IO模式 |
| 大IO压满 | 100% | 64KB+ | 高(>4) | 磁盘确实满了,考虑扩容 |
| 正常负载 | 60-80% | 16-32KB | 1-2 | 健康状态 |
避坑指南:我曾经被%util骗过一次,花了整整两天去换硬件,结果发现是应用层代码把一次大IO拆成了几百次小IO。后来我养成了习惯——先看avgrq-sz,再下结论。
4.2 IO等待过高:CPU在等谁?
iowait这个指标,很多人理解错了。它表示CPU空闲且等待IO完成的时间占比。说白了,CPU闲着没事干,在等磁盘把数据拿回来。
为什么会这样?你想想看,一个线程发起了read请求,磁盘还没返回数据,这个线程就被挂起了。如果这时候没有其他线程可以调度,CPU就进入了iowait状态。
我见过最夸张的一次,某台日志服务器的iowait飙到了70%。查下来发现是日志写入频率太高,而且每条日志都调用了fsync。每次写都要等磁盘刷完才返回,CPU能不等着吗?
排查iowait过高的步骤,我一般这么来:
- 先确认是哪个进程:用
iotop或pidstat -d看IO大户。 - 再看IO模式:用
iostat -x 1看r/s和w/s的比例,以及await和svctm的差值。 - 最后查文件系统层:用
strace跟踪系统调用,看是不是有频繁的fsync或sync。
注意:iowait高不一定就是磁盘慢。如果await很高但svctm很低,说明IO请求在排队,磁盘本身并不慢。这时候要优化的是IO调度策略或减少并发请求数。
4.3 单盘性能瓶颈:木桶最短的那块板
现在的存储系统,动不动就是RAID卡、SSD阵列、分布式存储。但很多时候,瓶颈就出在一块不起眼的单盘上。
我记得有一次帮客户排查一个Hadoop集群的性能问题。整个集群100多台机器,但总有那么几台任务跑得特别慢。查下来发现,这几台机器用的磁盘型号不一样,是上一批采购的旧款SATA盘,顺序读写还行,随机IO一塌糊涂。
单盘性能瓶颈的典型特征:
- 同一批次磁盘,某一块的
await明显高于其他盘:大概率是坏道或硬件老化。 - 磁盘的
svctm超过10ms:对于机械盘,10ms是正常上限;对于SSD,超过1ms就不正常了。 - 磁盘温度异常:超过60°C,性能会明显下降。
怎么解决?我个人的建议是:
- 如果是硬件故障,直接换盘。
- 如果是型号差异,把慢盘上的数据迁移走,或者降级使用(比如只放冷数据)。
- 如果是SSD,检查是不是写缓存满了。有些SSD在缓存写满后,性能会断崖式下跌。
4.4 文件系统锁竞争:看不见的隐形杀手
这个坑,很多新手根本想不到。磁盘利用率不高,IO等待也不高,但应用就是慢。查到最后,发现是文件系统内部的锁在打架。
文件系统为了保证数据一致性,会在元数据操作时加锁。比如创建文件、删除文件、修改权限、更新目录项,这些操作都需要拿锁。如果并发量太大,锁竞争就会导致线程阻塞。
我遇到过最典型的案例:一个图片上传服务,每秒要创建上千个小文件。磁盘是NVMe SSD,带宽和IOPS都绰绰有余,但应用就是卡。用perf top一看,热点函数全在ext4的inode_lock和dentry_lock上。
锁竞争的高危场景:
- 大量并发创建/删除小文件(如日志轮转、临时文件生成)
- 高并发目录操作(如同一个目录下成千上万个文件)
- 频繁的
stat和chmod操作
怎么排查?我一般用这几个工具:
perf lock:直接看内核锁的竞争情况。strace -c:统计系统调用的耗时,如果creat和unlink的耗时异常高,基本就是锁的问题。iostat -x:如果await高但svctm正常,说明IO在排队,而排队的原因可能是锁。
优化手段也简单:
- 用
dir_index和hashed_tree优化目录结构(ext4默认开启)。 - 把文件分散到多个子目录中,避免单目录文件过多。
- 考虑使用
XFS或Btrfs,它们在并发元数据操作上比ext4好一些。 - 如果实在不行,上
tmpfs或ramdisk,把锁竞争问题绕过去。
避坑指南:我曾经在一个高并发场景下,把ext4的inode_readahead_blks参数调大了,结果锁竞争更严重了。后来才明白,预读虽然能加速读,但也会延长锁的持有时间。调优参数一定要做A/B测试,别想当然。
嗯,这四个瓶颈,你只要记住一个原则:先确认症状,再定位根因,最后对症下药。不要看到100%就换盘,不要看到iowait高就加CPU。很多时候,问题出在应用层或文件系统层,跟硬件没关系。