磁盘故障排查实战:从IO使用率高到定位问题进程全攻略
前言
在Linux系统运维中,磁盘IO性能问题是最常见的故障之一。当系统响应变慢、应用卡顿时,往往与磁盘IO使用率过高有关。本文将系统性地介绍磁盘IO故障的排查方法,从系统级定位到进程级分析,帮助你快速找到问题根源。
一、快速判断:是否为IO问题引起的系统缓慢
当系统变慢时,首先需要确认是否由磁盘IO问题导致。
使用top命令查看CPU等待IO的占比
top
重点关注 %wa 这一列(CPU等待I/O的时间占比):
%Cpu(s): 2.5 us, 1.2 sy, 0.0 ni, 70.5 id, 25.6 wa, 0.0 hi, 0.2 si, 0.0 st
判断标准:
%wa < 10%:IO压力正常%wa 10%-30%:存在IO压力,需要关注%wa > 30%:IO压力较大,系统性能明显受影响%wa > 50%:IO严重瓶颈,系统响应极慢
注意:wa值高只说明CPU在等待IO,但具体是哪个磁盘、哪个进程需要进一步排查。
二、定位磁盘:哪个磁盘IO使用率高
使用 iostat 命令可以查看每个磁盘的IO使用情况。
安装sysstat工具包(包含iostat)
# CentOS/RHEL
yum install -y sysstat
# Ubuntu/Debian
apt-get install -y sysstat
查看磁盘IO统计信息
# 查看所有磁盘IO情况,每2秒刷新一次
iostat -x 2
# 查看指定磁盘,例如sda
iostat -x sda 2
关键指标解读:
| 指标 | 含义 | 参考阈值 |
|---|---|---|
%util |
磁盘繁忙程度(最重要的指标) | >70% 表示磁盘繁忙 |
r/s |
每秒读请求次数 | 数值越高IO越密集 |
w/s |
每秒写请求次数 | 数值越高IO越密集 |
rkB/s |
每秒读取的KB数 | - |
wkB/s |
每秒写入的KB数 | - |
await |
平均每次IO请求的等待时间(ms) | >10ms 可能存在问题 |
svctm |
平均每次IO请求的服务时间(ms) | - |
示例输出:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 45.00 102.00 512.00 2048.00 36.00 5.20 38.50 12.30 45.20 4.50 90.52
从这个示例可以看出:%util = 90.52%,说明sda磁盘已经非常繁忙,是系统性能瓶颈所在。
三、定位进程:哪个进程导致IO高
找到问题磁盘后,需要进一步找出是哪个进程在大量读写磁盘。
方法一:使用iotop命令(推荐)
iotop可以实时显示每个进程的IO读写情况,是最直观的工具。
安装iotop:
# CentOS/RHEL
yum install -y iotop
# Ubuntu/Debian
apt-get install -y iotop
常用命令:
# 实时查看进程IO情况
iotop
# 只显示有IO操作的进程
iotop -o
# 批量模式,输出到文件进行分析
iotop -botqqq --iter=3
# 筛选IO大于0.2MB/s的进程
iotop -botqqq --iter=3 | awk '{ if ($11 > 0.2) print }'
iotop输出解读:
Total DISK READ: 20.15 M/s | Total DISK WRITE: 45.32 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1234 be/4 mysql 15.20 M/s 30.15 M/s 0.00 % 95.32 % mysqld
5678 be/4 apache 2.50 M/s 8.20 M/s 0.00 % 45.12 % httpd
DISK READ/WRITE:实际磁盘读写速率IO>:进程在IO调度中消耗的时间百分比
方法二:通过/proc文件系统查看
如果无法安装iotop,可以通过 /proc 文件系统查看特定进程的IO统计。
# 先找到IO高的进程PID(通过top或ps)
top -d 2
# 查看指定进程的IO详情
cat /proc/[PID]/io
示例:查看mysqld进程(PID=3203)的IO情况
cat /proc/3203/io
输出示例:
rchar: 1246816249
wchar: 5987241452
syscr: 485723
syscw: 327168
read_bytes: 862653440
write_bytes: 5123723264
cancelled_write_bytes: 0
字段含义:
| 字段 | 含义 |
|---|---|
rchar |
读出的总字节数(含pagecache缓存) |
wchar |
写入的总字节数(含pagecache缓存) |
syscr |
read()/pread()系统调用次数 |
syscw |
write()/pwrite()系统调用次数 |
read_bytes |
实际从磁盘读取的字节数(重要指标) |
write_bytes |
实际写入磁盘的字节数(重要指标) |
cancelled_write_bytes |
截断pagecache导致的未写入字节数 |
注意:
rchar/wchar包含pagecache统计,不一定代表实际磁盘IO;read_bytes/write_bytes才是实际磁盘IO量。
方法三:使用pidstat工具
pidstat可以按进程统计IO使用情况。
# 查看指定进程的IO统计,每2秒输出一次,共5次
pidstat -d -p 12976 2 5
# 查看所有进程的IO统计
pidstat -d 2
输出示例:
Linux 3.10.0-957.el7.x86_64 (localhost) 04/22/2026 _x86_64_ (4 CPU)
10:15:30 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
10:15:32 AM 27 3203 1024.00 2048.00 0.00 mysqld
kB_rd/s:每秒从磁盘读取的KB数kB_wr/s:每秒写入磁盘的KB数kB_ccwr/s:每秒取消写入的KB数
四、排查特殊进程状态
1. 查看不可中断睡眠进程(D状态)
D状态进程通常是在等待IO(磁盘IO、网络IO等),大量D状态进程说明IO系统存在问题。
# 查看所有D状态进程
ps -eo state,ppid,pid,cmd | grep -e '^[Dd]'
# 更详细的D状态进程信息
ps aux | awk '$8=="D" {print $0}'
输出示例:
D 1234 1234 [kworker/0:0]
D 5678 5678 mysqld
D状态说明:
- 产生原因:进程等待磁盘IO时无法被中断,进入uninterruptible sleep状态
- 正常情况:短暂的D状态是正常的
- 异常情况:大量D状态进程或长时间D状态,说明IO系统可能存在故障
2. 查看僵尸进程(Z状态)
虽然僵尸进程不直接消耗IO资源,但大量僵尸进程会影响系统整体性能。
# 查看所有Z状态进程
ps -eo state,ppid,pid,cmd | grep -e '^[Zz]'
五、完整排查脚本
以下是一个完整的磁盘IO问题排查脚本:
#!/bin/bash
# disk_io_check.sh - 磁盘IO问题一键排查脚本
echo "========== 磁盘IO问题排查报告 =========="
echo "检查时间: $(date)"
echo ""
# 1. 查看系统负载和CPU等待IO情况
echo "【1】系统负载及CPU等待IO情况:"
top -bn1 | head -5
echo ""
# 2. 查看磁盘IO使用率
echo "【2】磁盘IO使用率(%util > 70% 表示繁忙):"
iostat -x 2 1 | grep -E "Device|sd|vd|nvme"
echo ""
# 3. 找出%util最高的磁盘
BUSY_DISK=$(iostat -x 2 1 | grep -E "sd|vd|nvme" | sort -k14 -rn | head -1 | awk '{print $1}')
if [ -n "$BUSY_DISK" ]; then
echo "【3】最繁忙的磁盘: $BUSY_DISK"
iostat -x $BUSY_DISK 2 1
fi
echo ""
# 4. 查看IO高的进程(如果有iotop)
if command -v iotop &> /dev/null; then
echo "【4】IO使用率最高的进程:"
iotop -botqqq --iter=1 2>/dev/null | head -10
else
echo "【4】iotop未安装,使用pidstat替代:"
pidstat -d 1 1 | head -10
fi
echo ""
# 5. 查看D状态进程
echo "【5】不可中断睡眠(D状态)进程:"
D_PROCS=$(ps -eo state,ppid,pid,cmd | grep -e '^[Dd]')
if [ -n "$D_PROCS" ]; then
echo "$D_PROCS"
else
echo "无D状态进程"
fi
echo ""
# 6. 查看Z状态进程
echo "【6】僵尸(Z状态)进程:"
Z_PROCS=$(ps -eo state,ppid,pid,cmd | grep -e '^[Zz]')
if [ -n "$Z_PROCS" ]; then
echo "$Z_PROCS"
else
echo "无Z状态进程"
fi
echo ""
# 7. 磁盘空间使用情况
echo "【7】磁盘空间使用情况:"
df -h | grep -E "Filesystem|/dev/sd|/dev/vd|/dev/nvme"
echo ""
# 8. 磁盘挂载参数
echo "【8】磁盘挂载参数(查看是否使用noatime等优化选项):"
mount | grep -E "/dev/sd|/dev/vd|/dev/nvme"
echo ""
echo "========== 排查完成 =========="
六、附录:iotop使用详解
iotop常用参数
| 参数 | 说明 |
|---|---|
-o, --only |
只显示有IO操作的进程 |
-b, --batch |
批量模式,适合输出到文件 |
-t, --time |
添加时间戳 |
-q, --quiet |
安静模式,减少输出行数 |
--iter=N |
迭代N次后退出 |
-d SEC, --delay=SEC |
设置刷新间隔(秒) |
-p PID |
只监控指定PID |
实用命令组合
# 实时监控,只显示有IO的进程
iotop -o
# 批量模式,输出3次,每次间隔2秒
iotop -botq --iter=3 --delay=2
# 监控特定进程
iotop -p 1234
# 输出到文件分析
iotop -botq --iter=10 > /tmp/iotop.log
# 筛选IO大于1MB/s的进程
iotop -botqqq --iter=3 | awk '{ if ($7 > 1024 || $9 > 1024) print }'
七、常见问题及解决方案
问题1:%util持续100%,但业务没有明显变慢
可能原因:
- 磁盘在做后台清理(如TRIM操作)
- 文件系统日志刷盘
- 使用了RAID卡,%util不能准确反映单盘状态
解决方法:
# 使用iostat查看更详细的指标
iostat -x 1
# 关注await和svctm,如果都正常,可能是正常现象
问题2:大量D状态进程,kill不掉
原因: 进程在等待IO,无法被中断
解决方法:
- 检查磁盘硬件是否有故障(dmesg查看内核日志)
- 检查文件系统是否损坏
- 最后手段:重启服务器
# 查看内核日志中的磁盘错误
dmesg | grep -i error
dmesg | grep -i fail
问题3:IO突然飙高后无法恢复
排查步骤:
# 1. 查看是否有大量D状态进程
ps aux | awk '$8=="D"'
# 2. 查看系统平均负载
uptime
# 3. 查看磁盘队列长度
iostat -x 1
# 关注avgqu-sz,如果持续大于10,说明IO堆积严重
八、总结
磁盘IO问题的排查思路总结为以下流程图:
系统响应慢
↓
top查看%wa是否过高 ────No──→ 排查其他原因(CPU/内存/网络)
↓ Yes
iostat查看%util确定繁忙磁盘
↓
iotop/pidstat定位具体进程
↓
分析进程行为(是否正常IO)
↓
解决问题(优化SQL、增加缓存、更换磁盘等)
核心命令速查表:
| 排查阶段 | 命令 | 关键指标 |
|---|---|---|
| 初步判断 | top |
%wa |
| 定位磁盘 | iostat -x 2 |
%util, await |
| 定位进程 | iotop -o |
DISK READ/WRITE |
| 进程详情 | cat /proc/[PID]/io |
read_bytes, write_bytes |
| 异常进程 | `ps -eo state,pid,cmd | grep '^D'` |
本文为原创内容,欢迎转载,请注明出处。

浙公网安备 33010602011771号