这个场景要解决什么
应用变慢、怀疑磁盘时,按层下钻比乱猜有效:先看设备层的利用率与延迟,再看哪个进程在读写,最后定位到具体文件与系统调用。每一层回答一个不同的问题——设备层回答哪块盘堵了,进程层回答谁在堵,文件层回答读写的是什么。层别对了,优化方向才有意义。
基本信息
| 适用场景 | 磁盘延迟高、吞吐下降、应用响应变慢 |
|---|---|
| 目标 | 定位到设备、进程与文件三级瓶颈 |
| 工具链 | iostat、iotop、pidstat、strace、lsof |
| 注意 | 数据库自带缓存时块层指标可能平淡,别死磕磁盘 |
第 1 步 设备层
第 1 步 设备层
iostat -xz 1 5 # -x 扩展指标,-z 隐藏空闲设备
# 重点看 %util、await、r/s、w/s 与队列长度第 2 步 进程层
第 2 步 进程层
iotop -oPa -b -n 2 | head -n 25
pidstat -d 1 3 | tail -n +3 | sort -k5 -rn | head
# 找出读写量最大的进程,再结合 ps 看它是什么服务第 3 步 文件与调用栈
第 3 步 文件与调用栈
lsof -p 1234 | grep -E 'REG|DIR' | head
strace -f -e trace=read,write,fsync -p 1234 -T 2>/dev/null | head -n 40
# -T 会显示每次调用的耗时,能直接看到哪一步慢第 4 步 排除缓存在捣乱
第 4 步 排除缓存在捣乱
grep -E 'Cached|Dirty|Writeback' /proc/meminfo
vmstat 1 3 # bi/bo 才是真实的块层活动
# 写入量集中在 Writeback,说明还在刷页缓存iostat 关键列
| 列 | 含义 | 怎么判 |
|---|---|---|
| %util | 设备忙碌时间占比 | 接近 100% 说明设备接近饱和 |
| await | 每个 IO 的平均等待加服务时间 | 机械盘上到两位数毫秒就要警觉 |
| r/s、w/s | 每秒读、写次数 | 要和队列深度一起看 |
| rkB/s、wkB/s | 每秒读写字节数 | 用来区分延迟问题与吞吐问题 |
| aqu-sz | 平均请求队列长度 | 持续升高说明设备来不及处理 |
| %iowait | CPU 等待 IO 的时间占比 | 仅为 CPU 侧统计,不代表整机 IO 压力 |
顺序建议是先看 %util 与 await 确认设备确实吃紧,再用 iotop 或 pidstat 找到进程,最后用 strace 看具体调用;跳过中间的进程归因,容易把缓存行为误当成磁盘故障。
小 IO 高频场景下 %util 达到 100% 未必说明设备到极限,先看 await 是否恶化;反过来 await 很漂亮而业务仍慢,问题多半不在磁盘。
从指标到结论
- 利用率高、await 高、队列长:设备确实到瓶颈,考虑加缓存或换更高性能的介质
- 利用率高、await 正常:多为小 IO 高频,可在应用侧考虑合并写
- 利用率不高、await 高:检查是否存在单笔大 IO,或存储链路上的问题
- 各项指标都低但业务慢:瓶颈不在磁盘,回到 CPU、内存或下游依赖上找
确认读写模式
确认读写模式
iostat -x 1 3 | grep -E 'Device|sda|sdb' # 看 r/s 与 w/s 的比例
iotop -oPa -b -n 1 | head -n 15 # 看是读多还是写多
cat /sys/block/sda/queue/scheduler # 查看当前 IO 调度器随机小 IO 密集的数据库盘值得调调度器与队列深度;以顺序读写为主的日志盘更依赖介质本身,调参数收益有限。
调优前先留一份基线:把当前的 iostat 与 iotop 输出存档,改动后再对比,否则很难判断改动是变好还是变坏。
容器与虚拟机的 IO 会先经过宿主机的存储栈,容器内看到的常是虚拟设备;要落到真实盘上,还得回到宿主机层面看。
有些看起来像 IO 故障的现象其实是磁盘写满:写入失败与重试同样会推高 await。动手查 IO 之前先 df -h 与 df -i 各看一眼,排除空间与 inode 耗尽的干扰。
定位到具体文件后先判断它是数据文件、日志还是索引:日志类可以调级别或改成异步写,数据文件更适合从索引设计和批量提交入手。
从现象到方向
| 现象 | 倾向原因 | 下一步 |
|---|---|---|
| 等待高但设备利用率低 | 请求小且数量多 | 看平均请求大小与发起进程 |
| 利用率高且队列深 | 设备层已到瓶颈 | 看读写模式与并发度 |
| 应用慢而块层平淡 | 被缓存或锁吸收 | 转查数据库与业务逻辑 |
| 周期性尖峰 | 定时任务叠加 | 把任务时刻与曲线对齐 |
| 持续高写入 | 落盘与归档策略 | 检查刷盘与日志配置 |
定位顺序是先看设备层是否饱和,再看是哪个进程发出的请求,最后确认读写模式以及是否被缓存掩盖。生产环境上做深入跟踪要限时并缩小范围,观测手段本身的开销有时足以把问题放大一级,务必在低峰或单实例上先验证方法。