myfreax

如何查找高 IO 等待的进程

当CPU负载峰值为60到80时。I/O等待会导致页面加载缓慢、超时和间歇性中断

7 min read
By myfreax
如何查找高 IO 等待的进程
如何查找高IO等待的进程

IO 等待或者 iowaitwaitwa%iowait,或者 wait% 通常可以通过 Linux 系统监控工具查看。例如命令行工具top、sar、atop等。

就其本身而言,它是众多性能统计数据之一,可让我们深入了解 Linux 系统性能。当单核 CPU 负载峰值为 60 到 80 时。

I/O 等待会导致页面加载缓慢、超时和间歇性中断。IO 等待是 CPU 或多个 CPU核心空闲的时间百分比,在此期间系统有等待的磁盘 I/O请求。

top 命令与 IO 等待

Linux 有很多可用的工具可以用来发现与排错,有些工具很容易使用,有些用法则比较高级。

查看 I/O 等待问题不仅需要使用一些高级工具,也需要一些基本工具的高级用法。I/O 等待之所以难以排查是因为有太多的工具告诉你系统 I/O 阻塞。

但没那么多工具可以帮你缩小范围以确定是哪个或哪些进程引起的问题。

在排查 IO 等待问题上,首先确定是不是因为 I/O 引起系统缓慢。你可以使用很多工具但最简单的 Linux 命令还是 top。

使用top命令即可看到类似这样的信息Cpu(s):  0.0%us,  0.5%sy,  0.0%ni, 99.5%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

us 用户空间占用 CPU 百分比。sy 内核空间占用CPU百分比。ni 用户进程空间内改变过优先级的进程占用 CPU 百分比。

id CPU 空闲百分比。wa CPU 等待 I/O 时间百分比。hi 硬件中断。si 软件中断。

top
 top - 14:31:20 up 35 min, 4 users, load average: 2.25, 1.74, 1.68
 Tasks: 71 total, 1 running, 70 sleeping, 0 stopped, 0 zombie
 Cpu(s): 2.3%us, 1.7%sy, 0.0%ni, 0.0%id, 96.0%wa, 0.0%hi, 0.0%si, 0.0%st
 Mem: 245440k total, 241004k used, 4436k free, 496k buffers
 Swap: 409596k total, 5436k used, 404160k free, 182812k cached

‌‌‌‌从 CPU(s) 这行你可以看出当前 CPU IO 等待的情况,越高的 wa 表示越多的 CPU 时间等待 I/O。

上面的 top 命令从系统层面展示 I/O 等待,但它没有告诉你哪个硬盘正在被影响,因此我们还需要使用 iostat 命令。

iostat 命令查找高 IO 等待的磁盘

iostat -x 2 5
 avg-cpu: %user %nice %system %iowait %steal %idle
  3.66 0.00 47.64 48.69 0.00 0.00

 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 44.50 39.27 117.28 29.32 11220.94 13126.70 332.17 65.77 462.79 9.80 2274.71 7.60 111.41
 dm-0 0.00 0.00 83.25 9.95 10515.18 4295.29 317.84 57.01 648.54 16.73 5935.79 11.48 107.02
 dm-1 0.00 0.00 57.07 40.84 228.27 163.35 8.00 93.84 979.61 13.94 2329.08 10.93 107.02

iostat -x 2 5 命令将每2秒打印报告,共打印5次。iostata 命令的 -x 选项可以打印详细的报告信息。

iostat 命令打印的第 1 个报告的数值是基于系统启动的时间。出于这个原因,在大部份情况下,iostat 命令打印出的第1个报告应该被忽略。

之后每个子报告都是基于上 1 次的报告。在这个例子中,iostat -x 2 5 命令将打印 5 次报告。

第 2 份报告就是从第 1 份报告开始后的硬盘数据,第 3 份报告基于第 2 份,依此类推。

上述示例,sda盘的 %utili 达到了 111.41%。这表示引起 I/O 等待的进程在写入 sda 磁盘。

因为我这个测试实例中只有 1 个硬盘,但对于有多硬盘的服务器来说,这可以缩小在使用 I/O 的进程范围。

iostat 命令除了提供 %utili 信息外,像 rrqm/s、wrqm/s 这些每秒读、写的请求数,r/s、w/s 每秒读写数也很有用。

iotop 命令查找高 IO 等待的进程

查看哪个进程使用硬盘最多,最简单的方法就是使用 iotop 命令。iotop 命令定期采样磁盘的读写数据。

显示每个进程磁盘读 DISK READ 和 DISK WRITE 写速度以及进程的 IO 优先级 PRIO 等信息。

通过查看磁盘的读 DISK READ 与写 DISK WRITE,我们很容易就可以确定是bonnie++ 进程在频繁的使用磁盘 IO。

iotop
 Total DISK READ: 8.00 M/s | Total DISK WRITE: 20.36 M/s
  TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
 15758 be/4 root 7.99 M/s 8.01 M/s 0.00 % 61.97 % bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp

ps 命令查找高 IO 等待的进程

虽然 iotop 很好用,但主流的 Linux 发行版并没有安装 iotop。系统管理员总是会碰到这样的情况,他们没办法在短时间内简单地安装这些非默认命令。

如果 iotop 没办法用,可以使用 ps 命令来代替 iotop 命令。以下的步聚也可以帮助你缩小进程的范围。

ps 命令可以打印进程的内存,CPU 的使用率。但没法查看进程的磁盘 I/O 情况。但它可以查看进程是否在等待磁盘 I/O。

ps 命令的 STAT 状态列提供进程当前的状态。D 表示不间断睡眠。R 正在运行。S 可中断的睡眠,正在等待事件的完成。T 已经终止进程。

X 表示进程已经死亡,你可能永远不会看到此状态。 Z 表示已失效,通常称为僵尸进程,已终止但未由其父进程回收。

等待 I/O 的进程通常处于 D 状态,通过 ps 命令打印的信息我们就可以找到正在等待磁盘 IO 的进程。

for x in `seq 1 1 10`; do ps -eo state,pid,cmd | grep "^D"; echo "----"; sleep 5; done
 D 248 [jbd2/dm-0-8]
 D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp

命令会每 5 秒循环打印处于 D 状态的进程,共打印 10 次。但仅凭进程处于 D 状态,还不能完全确定就是该进程引起的 I/O 等待。

为了确定可疑的进程,我们还需要使用 /proc 文件系统。在这个虚拟文件系统里,每个进程都有一个 IO 文件,里面的数值跟 iotop 命令获取的 I/O 数值是一样的。

假设,我们怀疑引起高 IO 等待的进程 bonnie++,它的进程 PID 是 16528。我们可以运行命令cat /proc/16528/io 查看进程磁盘IO数据。

cat /proc/16528/io
rchar: 562397689
wchar: 1073318747
syscr: 137395
syscw: 190792
read_bytes: 482344960
write_bytes: 524697984
cancelled_write_bytes: 16801792

read_byteswrite_bytes就这个进程读写硬盘的字节数。在这里,bonnie++已经读取了46MB,写入524MB的数据。

lsof 命令查看频繁读写的文件

lsof 命令会为你展示指定进程打开的所有文件,为了减少打印的信息,可以仅使用 -p 选项打印指定进程打开的文件。

lsof -p 16528

减少I/O等待

优化应用程序的代码和数据库查询。这可以大大降低磁盘读/写的频率。这应该是您的第一种方法。

确保您有足够的可用内存,使大约一半的服务器内存用于内存缓冲区和缓存,而不是使用交换空间分页到磁盘。

调整您的系统、存储设备和 Linux 内核以提高存储性能和使用寿命。最后,如果一切都失败了。将存储设备升级到更快的SSD、NVMe或其他高吞吐量存储设备。