最精准的方式是使用sudo iotop -o -P:其中,-o参数能够仅展示真正进行IO操作的进程,从而过滤掉95%的干扰信息;-P参数则只显示进程,不显示线程。DISK READ/WRITE列会呈现自动缩放后的实时带宽(单位为B/s/K/s/M/s),默认每秒刷新一次。若要按照IO等待时间进行排序,快速定位高延迟进程,可通过Shift+P组合键实现。

直接用 iotop -o -P 看实时带宽最准
不需要猜、不用写脚本,sudo iotop -o -P 是生产环境里最快定位“谁正在吃磁盘”的命令。它默认每秒刷新,DISK READ 和 DISK WRITE 两列就是当前进程的实时读写带宽(单位自动缩放为 B/s、K/s、M/s)。
-o是关键:只显示此刻真正在读写磁盘的进程,过滤掉内核线程和静默进程(比如[kthreadd]、[jbd2/sda-8]),否则屏幕 95% 是噪音-P避免线程干扰:同一进程多个线程会分散在不同行,加-P后只显示进程主干,方便快速比对- 界面中按
Shift+P可切换按IO>列排序——有些高频小文件操作的进程(如日志轮转)带宽不高,但 I/O 等待占比能到 90%+,靠这个更容易揪出来 - 别信默认不加参数的
iotop:没-o就等于在一堆 0.00 B/s 行里找数字,根本没法用
pidstat -d 1 更适合脚本化监控或看指定进程
如果你要写监控脚本、或者只想盯某几个进程(比如 mysqld 或某个 python 服务),pidstat -d 比 iotop 更轻量、输出更结构化。
- 必须带时间间隔,例如
pidstat -d 1:不带参数只输出一次快照;pidstat -d 0会卡死终端,千万别试 - 盯
rkB/s和wkB/s这两列:单位是 KB/s,不是累计值,也不是缓存命中量,就是真实块设备读写速率 - 查特定进程推荐用
pgrep配合:pidstat -d 2 -p "$(pgrep -f 'gunicorn.*wsgi')",比手动ps aux | grep更可靠(尤其命令含空格或路径不一致时) - 注意:非 root 用户运行会漏掉 systemd、内核线程等,且对容器内进程显示的是宿主机视角的 IO,不是 cgroup 限制后的值
为什么不能只看 /proc/[pid]/io 的 read_bytes/write_bytes
这两个字段反映的是累计磁盘读写字节数,不是带宽。想算带宽,得自己做差值再除以时间——但容易踩坑。
read_bytes确实只统计实际从块设备读入的字节(不含 page cache 命中),但它不包含时间戳,两次cat /proc/1234/io | grep read_bytes的差值,依赖你采样时机是否稳定- 如果进程刚完成一次大读取,你恰好在它休眠时采样,差值就为 0;而它下一秒又开始读,你又错过——看起来“带宽为 0”,其实只是节奏错位
iotop和pidstat底层也是轮询这个文件,但它们做了平滑采样(默认 1 秒周期),结果更接近人眼可感知的“实时”- 真正容易被忽略的是:
read_bytes不等于物理磁盘实际读取量——比如 RAID 卡或 NVMe 控制器内部重试、对齐写入,内核统计不到
看到高 IO 别急着 kill,先分清是“进程贪”还是“磁盘弱”
iotop 或 pidstat 告诉你“谁在读写”,但不告诉你“为什么慢”或“是不是真有问题”。这时候得交叉验证。
- 如果
iotop显示ja va进程DISK WRITE一直 30M/s,先跑iostat -x 1看设备级指标:await > 20ms或%util > 80%(SATA/SSD 场景下)说明磁盘已饱和,杀进程没用 rsync或tar高 IO 是正常行为,但要用cat /proc/确认它真在备份业务数据,而不是误操作扫了整个/cmdline | tr ' ' ' ' /mysqld持续高写入,可能是innodb_log_file_size太小导致 checkpoint 频繁,查SHOW ENGINE INNODB STATUS里的 Log sequence number 差值比看 IO 更准- 真正容易被忽略的是:IO 高可能只是表象。比如
ja va进程SWAPIN%也高,说明内存不足在 swap,此时 IO 高是副作用——该看free -h和vmstat 1,而不是继续优化磁盘