磁盘IO过高,如何定位有问题的进程

最近工作中收到了几次磁盘IO过高的报警,忽然间发现,自己对于如何处理这类问题,没有一点经验,经过一些摸索,总算入了点门道。

报警的机器上,只有一个jupyterhub服务,想来应该是某个notebook做了IO密集型的任务,所以第一步,查看容器的资源消耗情况

1. 查看容器资源消耗情况

使用命令 docker stats 可以查看所有容器的资源消耗情况,如果想查看单个容器的,可以在命令后面跟上容器的ID

docker stats

CONTAINER           CPU %               MEM USAGE / LIMIT       MEM %               NET I/O               BLOCK I/O             PIDS
9c358cd5dbd9        0.27%               201 MiB / 32 GiB        0.61%               0 B / 0 B             540.7 kB / 192.5 kB   54
8e98e5775497        0.24%               98.97 MiB / 32 GiB      0.30%               0 B / 0 B             610.3 kB / 32.77 kB   204
43749640edab        0.45%               794.6 MiB / 32 GiB      2.42%               0 B / 0 B             241.7 kB / 444.4 MB   326
4fb2fc4c8371        0.66%               31.74 GiB / 32 GiB      99.19%              0 B / 0 B             389.4 GB / 23.29 GB   473

BLOCK I/O 是容器IO资源消耗情况, 可以看到有一个容器IO比其他容器大很多,这个数值只是记录了容器过去的IO总量,不代表现在IO也很高。

2. 查看磁盘使用信息

iostat -x 1 10

查看磁盘使用信息,每秒输出一次,连续输出10次

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.02    0.00    1.20    0.02    0.00   96.75

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    13.63    3.21    5.97    56.37   255.45    67.96     0.00    0.32    0.69    0.12   0.12   0.11
sdb               0.00     0.13   14.39    8.75   515.61   554.60    92.48     0.33   14.13    4.53   29.92   0.31   0.71

rkB/s 和 wkB/s 过高都说明磁盘IO过高,其他字段说明如下:

  1. Device:设备名称
  2. tps:每秒的IO读、写请求数量,多个逻辑请求可以组合成对设备的单个I/O请求。
  3. Blk_read/s (kB_read/s, MB_read/s):从设备读取的数据量,以每秒若干块(千字节、兆字节)表示。块相当于扇区,因此块大小为512字节。
  4. Blk_wrtn/s (kB_wrtn/s, MB_wrtn/s):写入设备的数据量,以每秒若干块(千字节、兆字节)表示。块相当于扇区,因此块大小为512字节。
  5. Blk_read (kB_read, MB_read):读取块的总数(千字节、兆字节)。
  6. Blk_wrtn (kB_wrtn, MB_wrtn):写入块的总数(千字节,兆字节)。

  7. rrqm/s:每秒合并到设备的读请求数。即delta(rmerge)/s

  8. wrqm/s:每秒合并到设备的写入请求数。即delta(wmerge)/s

  9. r/s:每秒完成的读I/O设备次数。即delta(rio)/s

  10. w/s:每秒完成的写I/0设备次数。即delta(wio)/s
    rsec/s (rkB/s, 11. rMB/s):每秒读取设备的扇区数(千字节、兆字节)。每扇区大小为512字节

  11. wsec/s (wkB/s, wMB/s):每秒写入设备的扇区数(千字节、兆字节)。每扇区大小为512字节

  12. avgrq-sz:平均每次设备I/O操作的数据量(扇区为单位)。即delta(rsec+wsec)/delta(rio+wio)

  13. avgqu-sz:平均每次发送给设备的I/O队列长度。

  14. await:平均每次IO请求等待时间。(包括等待队列时间和处理时间,毫秒为单位)

  15. r_await:平均每次IO读请求等待时间。(包括等待队列时间和处理时间,毫秒为单位)

  16. w_await:平均每次IO写请求等待时间。(包括等待队列时间和处理时间,毫秒为单位)

  17. svctm:平均每次设备I/O操作的处理时间(毫秒)。警告!不要再相信这个字段值,这个字段将在将来的sysstat版本中删除。

  18. %util:一秒中有百分之多少的时间用于I/O操作,或者说一秒中有多少时间I/O队列是非空的。当该值接近100%时,设备饱和发生

3. 找到IO占用高的进程

前面的方法只是大致的查看一下磁盘IO的情概况,并没有具体的定位到哪个进程占用IO,要想知道哪个进程有问题,可以使用iotop

iotop -oP

Total DISK READ :       0.00 B/s | Total DISK WRITE :      19.88 M/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:      77.59 K/s
   PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                               
  3333 be/3 root        0.00 B/s   26.99 K/s  0.00 %  0.21 % [jbd2/sdb1-8]
 11625 be/4 tomcat      0.00 B/s   19.84 M/s  0.00 %  0.00 % python -m ipykernel_launcher -f /hom~b6c-9571-4e91-b350-42bc69648908.json
144303 be/4 root        0.00 B/s    3.37 K/s  0.00 %  0.00 % java -jar -Xms512m -Xmx512m -Xmn256m~s-turtle-task.jar --server.port=8718
 68689 be/4 tomcat      0.00 B/s    6.75 K/s  0.00 %  0.00 % java -cp /usr/local/spark/conf/:/usr~python=./pyenv/jupyterhub/bin/python
  3416 be/4 root        0.00 B/s    6.75 K/s  0.00 %  0.00 % supervise falcon-agent

这个命令可以查看到进程的pid, 读写量,IO百分比,以及涉及到的命令,这样就容易定位问题了,除了这个命令,还可以使用pidstat

pidstat -d 1

Linux 3.10.0-1062.el7.x86_64 (kwsy)   03/04/2021      _x86_64_        (40 CPU)

10:35:07 AM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
10:35:08 AM     0       985      0.00     53.85      0.00  jbd2/sda3-8
10:35:08 AM     0      3416      0.00      7.69      0.00  supervise
10:35:08 AM     0      4253      0.00      7.69      0.00  dockerd

效果是一样的。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案