Linux disk 100% busy,谁造成的?

Stella981
• 阅读 573

disk 100% busy,谁造成的?

2016/11/16 vmunix

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

# iostat -xd ... 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 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 ...

1

2

3

4

5

6

7

8

9

# iostat -xd

...

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 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_accounting ioac; ... };

1

2

3

4

5

struct task_struct {

...

struct task_io_accounting ioac;

...

};

可以直接在 /proc//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

1

2

3

4

5

6

7

8

# 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//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

1

2

3

4

5

6

7

8

# 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:

Actual DISK READ: 3.31 M/s | Actual DISK WRITE: 0.00 B/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 14772 be/4 root 3.31 M/s 0.00 B/s 0.00 % 61.99 % dd if=/delag=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] ...

1

2

3

4

5

6

Actual DISK READ: 3.31 M/s | Actual DISK WRITE: 0.00 B/s

TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO> COMMAND

14772 be/4 root 3.31 M/s 0.00 B/s 0.00 % 61.99 % dd if=/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) } probe kernel.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) }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#! /usr/bin/env stap

global device_of_interest

probe begin {

device_of_interest = $1

printf ("device of interest: 0x%x\n", device_of_interest)

}

probe kernel.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)

}

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

# ll /dev/sdb brw-rw----. 1 root disk 8, 16 Oct 24 15:52 /dev/sdb Major number(12-bit): 8 i.e. 0x8 Minor number(20-bit): 16 i.e. 0x00010 合在一起得到设备号: 0x800010

1

2

3

4

5

6

# ll /dev/sdb

brw-rw----. 1 root disk 8, 16 Oct 24 15:52 /dev/sdb

Major number(12-bit): 8 i.e. 0x8

Minor number(20-bit): 16 i.e. 0x00010

合在一起得到设备号: 0x800010

执行脚本,我们看到:

# ./dev_task_io.stp 0x800010 device of interest: 0x800010 [dd](31202) dev:0x800010 rw:0 size:512 [dd](31202) dev:0x800010 rw:0 size:512 [dd](31202) dev:0x800010 rw:0 size:512 [dd](31202) dev:0x800010 rw:0 size:512 [dd](31202) dev:0x800010 rw:0 size:512 ...

1

2

3

4

5

6

7

8

# ./dev_task_io.stp 0x800010

device of interest: 0x800010

[dd](31202) dev:0x800010 rw:0 size:512

[dd](31202) dev:0x800010 rw:0 size:512

[dd](31202) dev:0x800010 rw:0 size:512

[dd](31202) dev:0x800010 rw:0 size:512

[dd](31202) dev:0x800010 rw:0 size:512

...

结果很令人满意,我们看到是进程号为31202的dd命令在对/dev/sdb进行读操作。

转载自:

linuxperf.com/?cat=11

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这