排查 Linux 下导致磁盘 I/O 使用率高的进程是一个常见的性能诊断任务。

核心思路

  1. 确认问题:首先确认确实是磁盘 I/O 瓶颈,而不是 CPU 或内存问题。
  2. 全局视角:找到哪个磁盘或分区压力大。
  3. 进程视角:定位是哪个(哪些)进程正在大量读写该磁盘。
  4. 深入分析:分析该进程的具体操作(读写哪些文件、系统调用等)。

第 1 步:确认全局磁盘 I/O 状况

使用 iostat 工具(来自 sysstat 包)来确认是否是磁盘 I/O 问题,并找出有压力的磁盘。

# 安装 sysstat(如果尚未安装)
# Ubuntu/Debian
sudo apt update && sudo apt install sysstat

# CentOS/RHEL/Fedora
sudo yum install sysstat      # 或 sudo dnf install sysstat

# 使用 iostat,每 2 秒刷新一次,显示扩展信息
iostat -dx 2

关键指标解读:

  • Device: 磁盘设备名(如 sda, vda, nvme0n1)。
  • r/sw/s: 每秒的读、写请求数量(IOPS)。
  • rkB/swkB/s: 每秒读、写的数据量(吞吐量)。
  • await: 每个 I/O 请求的平均等待时间(毫秒)。这是衡量磁盘延迟的关键指标,值越大说明排队越严重。
  • %util: 磁盘设备的利用率百分比。如果持续接近 100%,说明该磁盘设备已饱和,确实是 I/O 瓶颈。

示例输出:

Device            r/s     w/s     rkB/s     wkB/s   await  %util
sda              0.00  485.00      0.00  59420.00  120.33  98.20

这里清楚显示 sda 磁盘的写入压力极大(%util 为 98.2%,await 高达 120ms)。


第 2 步:定位高 I/O 的进程

一旦确认了问题磁盘(例如 sda),下一步就是找出罪魁祸首。

方法一:使用 iotop(最直接、最常用)

iotop 类似于 top,但专门用于监视磁盘 I/O。它按进程或线程显示实时 I/O 使用情况。

# 安装 iotop
# Ubuntu/Debian
sudo apt install iotop

# CentOS/RHEL/Fedora
sudo yum install iotop      # 或 sudo dnf install iotop

# 运行 iotop(需要 root 权限)
sudo iotop

使用技巧:

  • 排序:默认按 I/O 使用率排序。按左右箭头键可以按不同列排序(如读、写)。
  • 只显示有 I/O 的进程:按下 o 键或 --only 参数。
  • 刷新间隔-d 参数指定刷新秒数,例如 sudo iotop -d 2
  • 查看累计 I/O:加上 -a 参数显示累计数据而不是实时速率。

输出解读:

Total DISK READ: 0.00 B/s | Total DISK WRITE: 59.42 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
 4560 be/4 mysql       0.00 B/s   59.42 M/s  0.00 % 99.99 % mysqld

这里一目了然地看到 mysqld 进程(线程 ID 4560)正在以约 60MB/s 的速度写入磁盘,并且 I/O 占用时间高达 99.99%。

方法二:使用 pidstat(sysstat 套件的一部分)

pidstat 非常强大,可以按进程报告 I/O 统计信息,并且可以记录历史数据。

# 监控所有进程的 I/O,每 2 秒刷新一次
sudo pidstat -d 2

# 只监控某个特定进程(找到PID后)
sudo pidstat -d -p <PID> 2

输出解读:

Linux 5.4.0-...    06/10/2023      _x86_64_        (4 CPU)

03:15:20 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
03:15:22 PM   112      4560      0.00  59420.00      0.00  mysqld
  • kB_rd/s: 每秒从磁盘读取的数据量 (KB)。
  • kB_wr/s: 每秒向磁盘写入的数据量 (KB)。这里明确显示 mysqld 在大量写入。

第 3 步:深入分析特定进程

找到可疑进程后(例如 mysqld ),需要进一步分析它在做什么。

方法一:使用 lsof 查看进程打开的文件

查看该进程当前打开了哪些文件,特别是正在频繁读写的文件。

# 列出指定进程(PID)打开的所有文件
sudo lsof -p <PID>

# 结合 grep 过滤,例如只查看正在写入的文件(deleted状态可能是日志文件被rotate)
sudo lsof -p <PID> | grep -E "REG.*W|DEL"

# 或者,直接查看某个磁盘设备上被哪些文件占用
sudo lsof /dev/sda
方法二:使用 strace 跟踪系统调用(高级)

strace 可以跟踪进程发起的所有系统调用,包括 read, write, open, sync 等,这能告诉你进程在具体读写什么。

# 跟踪一个正在运行的进程的系统调用,重点关注文件操作
sudo strace -ff -p <PID> -e trace=file,write,read -s 1024 -o /tmp/strace_output.txt

# 参数解释:
# -ff: 跟踪所有子线程
# -p <PID>: 指定进程ID
# -e trace=file,write,read: 只跟踪文件、读、写相关的调用
# -s 1024: 显示字符串的前1024个字符(避免截断文件名)
# -o: 输出到文件

注意strace 开销较大,不建议在生产环境长时间运行。

方法三:使用 /proc 文件系统

/proc/<PID>/io 文件包含了该进程的累计 I/O 统计信息。

# 查看进程的累计I/O
sudo cat /proc/<PID>/io

输出示例:

rchar: 12345678
wchar: 987654321
syscr: 120
syscw: 450
read_bytes: 4096000    # 该进程从存储层读取的物理字节数
write_bytes: 20480000  # 该进程向存储层写入的物理字节数

你可以间隔一段时间(如 10 秒)读取一次 read_byteswrite_bytes,然后计算差值来估算实时速率。


总结与排查流程图

  1. 全局检查iostat -dx 2

    • 目标:确认 %utilawait 是否过高,找到压力大的磁盘(如 sda)。
  2. 定位进程

    • 首选sudo iotop (直观,实时)
    • 替代sudo pidstat -d 2 (更详细,可记录)
  3. 深入分析

    • 看文件sudo lsof -p <PID>
    • 看操作sudo strace -p <PID> ... (高级调试)
    • 看统计sudo cat /proc/<PID>/io

常见高 I/O 进程场景:

  • 数据库(MySQL, PostgreSQL):写日志、刷脏页、大查询。
  • 日志服务(rsyslog, journald, 应用日志):大量写日志文件。
  • 备份工具(rsync, tar, cp):大量文件读写。
  • 包管理器(apt, yum):更新软件时的大量下载和解压。
  • 虚拟机/容器:磁盘镜像的读写操作。

通过以上步骤,你就能系统地定位并解决 Linux 服务器上的磁盘 I/O 瓶颈问题。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐