剑客
关注科技互联网

disk 100% busy,谁造成的?

iostat等命令看到的是系统级的统计,比如下例中我们看到/dev/sdb很忙,如果要追查是哪个进程导致的I/O繁忙,应该怎么办?

# iostat -xd
...
Device:        rrqm/s  wrqm/s    r/s    w/s    rkB/s    wkB/s avgrq-szavgqu-sz  awaitr_awaitw_await  svctm  %util
sda              0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  0.00  0.00
sdb              0.00    0.00 6781.67    0.00  3390.83    0.00    1.00    0.85    0.13    0.13    0.00  0.13  85.03
dm-0              0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  0.00  0.00
dm-1              0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  0.00  0.00
dm-2              0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  0.00  0.00
...

进程的内核数据结构中包含了I/O数量的统计:

struct task_struct {
...
        struct task_io_accountingioac;
...
};

可以直接在 /proc/<pid>/io 中看到:

# cat /proc/3088/io
rchar: 125119 //在read(),pread(),readv(),sendfile等系统调用中读取的字节数
wchar: 632    //在write(),pwrite(),writev(),sendfile等系统调用中写入的字节数
syscr: 111    //调用read(),pread(),readv(),sendfile等系统调用的次数
syscw: 79    //调用write(),pwrite(),writev(),sendfile等系统调用的次数
read_bytes: 425984 //进程读取的物理I/O字节数,包括mmap pagein,在submit_bio()中统计的
write_bytes: 0    //进程写出的物理I/O字节数,包括mmap pageout,在submit_bio()中统计的
cancelled_write_bytes: 0 //如果进程截短了cache中的文件,事实上就减少了原本要发生的写I/O

我们关心的是实际发生的物理I/O,从上面的注释可知,应该关注 read_bytes 和 write_bytes。请注意这都是历史累计值,从进程开始执行之初就一直累加。如果要观察动态变化情况,可以使用 pidstat 命令,它就是利用了/proc/<pid>/io 中的原始数据计算单位时间内的增量:

# pidstat -d 2 2
Linux 3.10.0-229.14.1.el7.x86_64 (bj71s060)    11/16/2016      _x86_64_      (2 CPU)
 
12:30:15 PM  UID      PID  kB_rd/s  kB_wr/s kB_ccwr/s  Command
12:30:17 PM    0    14772  3362.25      0.00      0.00  dd
 
12:30:17 PM  UID      PID  kB_rd/s  kB_wr/s kB_ccwr/s  Command
12:30:19 PM    0    14772  3371.25      0.00      0.00  dd

另外还有一个常用的命令 iotop 也可以观察进程的动态I/O:

ActualDISKREAD:      3.31 M/s | ActualDISKWRITE:      0.00 B/s
  TID  PRIO  USER    DISKREAD  DISKWRITE  SWAPIN    IO>    COMMAND          
14772 be/4 root        3.31 M/s    0.00 B/s  0.00 % 61.99 % ddif=/de~lag=direct
    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd -~rialize 24
    2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
...

pidstat 和 iotop 也有不足之处,它们无法具体到某个硬盘设备,如果系统中有很多硬盘设备,都在忙,而我们只想看某一个特定的硬盘的I/O来自哪些进程,这两个命令就帮不上忙了。怎么办呢?可以用上万能工具SystemTap。比如:我们希望找出访问/dev/sdb的进程,可以用下列脚本,它的原理是对submit_bio下探针:

#! /usr/bin/env stap
 
global device_of_interest
 
probe begin {
  device_of_interest = $1
  printf ("device of interest: 0x%x/n", device_of_interest)
}
 
probekernel.function("submit_bio")
{
  dev = $bio->bi_bdev->bd_dev
  if (dev == device_of_interest)
    printf ("[%s](%d) dev:0x%x rw:%d size:%d/n",
            execname(), pid(), dev, $rw, $bio->bi_size)
}

这个脚本需要在命令行参数中指定需要监控的硬盘设备号,得到这个设备号的方法如下:

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址