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

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

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

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

# pidstat -d
Linux 3.10.-229.14..el7.x86_64 (bj71s060) // _x86_64_ ( CPU) :: PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
:: PM 3362.25 0.00 0.00 dd :: PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
:: PM 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
be/ root 3.31 M/s 0.00 B/s 0.00 % 61.99 % dd if=/de~lag=direct
be/ root 0.00 B/s 0.00 B/s 0.00 % 0.00 % systemd -~rialize
be/ 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 = $
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----. root disk , Oct : /dev/sdb Major number(-bit): i.e. 0x8
Minor number(-bit): i.e. 0x00010
合在一起得到设备号: 0x800010 注意是十六进制

执行脚本,我们看到:

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

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

相关内容:

Linux的设备管理是和文件系统紧密结合的,把设备和文件关联起来,这样系统调用可以直接用操作文件一样的方法来操作设备。

各种设备都以文件的形式存放在/dev目录下,称为设备文件。

应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。

为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。

主设备号用来区分不同类型的设备,而次设备号用来区分同一类型内的多个设备(及其设备分区)。

查看主设备号:  cat /proc/devices
查看当前设备的主次设备号: ls -l /dev

一个Linux系统,当前所有注册设备的主设备号可以通过/proc接口查看:

[root@localhost lenky]# cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
21 sg
29 fb
99 ppdev
116 alsa
128 ptm
136 pts
162 raw
180 usb
189 usb_device
202 cpu/msr
203 cpu/cpuid
251 hidraw
252 usbmon
253 bsg
254 rtc Block devices:
1 ramdisk
2 fd
259 blkext
7 loop
8 sd
9 md
11 sr
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
253 device-mapper
254 mdp
[root@localhost lenky]#

字符设备与块设备的主设备号并不冲突,所有两个都可以有主设备号为1的设备,如果要继续查看次设备号,那么可以通过直接ls -l来查看,比如查看主设备号为8的设备的次设备号:

[root@localhost lenky]# ls -Rl /dev/* | grep " 8,"
brw-rw----. 1 root disk 8, 0 Jan 12 06:24 /dev/sda
brw-rw----. 1 root disk 8, 1 Jan 12 06:24 /dev/sda1
brw-rw----. 1 root disk 8, 2 Jan 12 06:24 /dev/sda2
brw-rw----. 1 root disk 8, 16 Jan 12 06:25 /dev/sdb
brw-rw----. 1 root disk 8, 17 Jan 12 06:25 /dev/sdb1
brw-rw----. 1 root disk 8, 32 Jan 12 06:29 /dev/sdc
brw-rw----. 1 root disk 8, 33 Jan 12 06:29 /dev/sdc1
brw-rw----. 1 root disk 8, 34 Jan 12 06:29 /dev/sdc2
brw-rw----. 1 root disk 8, 35 Jan 12 06:29 /dev/sdc3
[root@localhost lenky]#

上面的0,1,2,16,17等都是次设备号,用于区分标记各个sd硬盘或分区。查看系统所有的块设备:

[root@localhost lenky]# grep ^ /sys/class/block/*/dev
/sys/class/block/dm-0/dev:253:0
/sys/class/block/dm-1/dev:253:1
/sys/class/block/dm-2/dev:253:2
/sys/class/block/fd0/dev:2:0
/sys/class/block/loop0/dev:7:0
/sys/class/block/loop1/dev:7:1
/sys/class/block/loop2/dev:7:2
/sys/class/block/loop3/dev:7:3
/sys/class/block/loop4/dev:7:4
/sys/class/block/loop5/dev:7:5
/sys/class/block/loop6/dev:7:6
/sys/class/block/loop7/dev:7:7
/sys/class/block/ram0/dev:1:0
/sys/class/block/ram10/dev:1:10
/sys/class/block/ram11/dev:1:11
/sys/class/block/ram12/dev:1:12
/sys/class/block/ram13/dev:1:13
/sys/class/block/ram14/dev:1:14
/sys/class/block/ram15/dev:1:15
/sys/class/block/ram1/dev:1:1
/sys/class/block/ram2/dev:1:2
/sys/class/block/ram3/dev:1:3
/sys/class/block/ram4/dev:1:4
/sys/class/block/ram5/dev:1:5
/sys/class/block/ram6/dev:1:6
/sys/class/block/ram7/dev:1:7
/sys/class/block/ram8/dev:1:8
/sys/class/block/ram9/dev:1:9
/sys/class/block/sda1/dev:8:1
/sys/class/block/sda2/dev:8:2
/sys/class/block/sda/dev:8:0
/sys/class/block/sdb1/dev:8:17
/sys/class/block/sdb/dev:8:16
/sys/class/block/sdc1/dev:8:33
/sys/class/block/sdc2/dev:8:34
/sys/class/block/sdc3/dev:8:35
/sys/class/block/sdc/dev:8:32
/sys/class/block/sr0/dev:11:0
[root@localhost lenky]#

关于每个主设备号:次设备号对应设备的功能在Linux帮助文档里可以找到:http://lxr.linux.no/#linux+v2.6.38.8/Documentation/devices.txt

在内核2.6.9之后,Linux系统上出现了一种名为device-mapper的存储映射机制,这种机制的作用简单来说就是给用户提供简单方便而又丰富的存储管理接口,在这种机制以及相关工具的帮助下,用户能够方便的自定义存储资源管理策略。

通过一些映射规则,device-mapper机制能够从原有的物理磁盘或逻辑磁盘中划分映射出新的逻辑磁盘,可以看到这是一个递归的映射机制,理论上可无限迭代。举个例子,系统有物理磁盘A和B,从物理磁盘A中映射出新的逻辑磁盘C、D、E,从物理磁盘B中映射出新的逻辑磁盘F、G,又可以从物理磁盘A和逻辑磁盘F中映射出新的逻辑磁盘H,等等。关于这方面,请参考:http://www.ibm.com/developerworks/cn/linux/l-devmapper/http://sources.redhat.com/dm/等资源,不管是原物理磁盘还是通过device-mappe机制映射出来的新逻辑磁盘,在Linux操作系统看来都一样,一切皆文件,复杂逻辑被隔离在底部。

[root@localhost lenky]# ls -Rl /dev/* | grep " 8,"
brw-rw----. 1 root disk 8, 0 Jan 12 06:24 /dev/sda
brw-rw----. 1 root disk 8, 1 Jan 12 06:24 /dev/sda1
brw-rw----. 1 root disk 8, 2 Jan 12 06:24 /dev/sda2

一般说的各个分区相加等于硬盘,有个隐含说明就是硬盘内各个分区的硬盘存储空间容量相加等于硬盘的硬盘存储空间容量。

一个硬盘有一个描述硬盘的信息,而一个分区有一描述分区的信息,将硬盘内各个分区的描述分区的信息拼接在一起也得不到关于硬盘的信息,所以给硬盘配上一个次设备号是有必要不多余的。

[root@localhost lenky]# ls -Rl /dev/* | grep " 8,"
brw-rw----. 1 root disk 8, 0 Jan 12 06:24 /dev/sda
brw-rw----. 1 root disk 8, 1 Jan 12 06:24 /dev/sda1
brw-rw----. 1 root disk 8, 2 Jan 12 06:24 /dev/sda2
brw-rw----. 1 root disk 8, 16 Jan 12 06:25 /dev/sdb
brw-rw----. 1 root disk 8, 17 Jan 12 06:25 /dev/sdb1
brw-rw----. 1 root disk 8, 32 Jan 12 06:29 /dev/sdc
brw-rw----. 1 root disk 8, 33 Jan 12 06:29 /dev/sdc1
brw-rw----. 1 root disk 8, 34 Jan 12 06:29 /dev/sdc2
brw-rw----. 1 root disk 8, 35 Jan 12 06:29 /dev/sdc3

我们看到/dev/sd*设备名的设备类型(即指的是IDE硬盘),这里有三个不同的IDE硬盘,其主设备号以及其分区的主设备号都是8。

DISK 100% BUSY,谁造成的?(ok)的更多相关文章

  1. Linux disk 100% busy,谁造成的?

    disk 100% busy,谁造成的? 2016/11/16 vmunix iostat等命令看到的是系统级的统计,比如下例中我们看到/dev/sdb很忙,如果要追查是哪个进程导致的I/O繁忙,应该 ...

  2. DISK 100% BUSY,谁造成的?

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

  3. Redis 5种数据结构使用及注意事项

    1优缺点 非常非常的快,有测评说比Memcached还快(当大家都是单CPU的时候),而且是无短板的快,读写都一般的快,所有API都差不多快,也没有MySQL Cluster.MongoDB那样更新同 ...

  4. 深入剖析 redis AOF 持久化策略

    本篇主要讲的是 AOF 持久化,了解 AOF 的数据组织方式和运作机制.redis 主要在 aof.c 中实现 AOF 的操作. 数据结构 rio redis AOF 持久化同样借助了 struct ...

  5. 关于Redis的常识(推荐)

    原文出处: https://github.com/springside/springside4/wiki/redis 版本:V3.0.3 2013-8-1 (@江南白衣版权所有,转载请保留出处) 1. ...

  6. 关于Redis的知识汇总[转]

    1. Overview 1.1 资料 <The Little Redis Book> ,最好的入门小册子,可以先于一切文档之前看,免费. 作者Antirez的博客,Antirez维护的Re ...

  7. 【OS】NMON的简介和使用

    [OS]NMON的简介和使用 目前NMON已开源,以sourceforge为根据地,网址是http://nmon.sourceforge.net. 1. 目的 本文介绍操作系统监控工具Nmon的概念. ...

  8. 深入学习Redis(2):持久化

    前言 在上一篇文章中,介绍了Redis的内存模型,从这篇文章开始,将依次介绍Redis高可用相关的知识——持久化.复制(及读写分离).哨兵.以及集群. 本文将先说明上述几种技术分别解决了Redis高可 ...

  9. 深入Redis持久化

    转载:https://segmentfault.com/a/1190000017193732 一.Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义. 我们知 ...

随机推荐

  1. leetcode — decode-ways

    /** * Source : https://oj.leetcode.com/problems/decode-ways/ * * * A message containing letters from ...

  2. angr进阶(3) 添加约束

    如果已知字符串长度或部分,可以使用如下的方式进行格式规范csaw_wyvern 1 flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range ...

  3. .NET Core GC 的设计

    此文章转载自:http://www.cnblogs.com/zkweb/p/6288457.html 作者: Maoni Stephens ( @maoni0) - 2015 提示: 推荐看 The ...

  4. Mybatis动态SQL简单了解 Mybatis简介(四)

    动态SQL概况 MyBatis 的强大特性之一便是它的动态 SQL 在Java开发中经常遇到条件判断,比如: if(x>0){ //执行一些逻辑........ }   Mybatis应用中,S ...

  5. ssh转发代理:ssh-agent用法详解

    SSH系列文章: SSH基础:SSH和SSH服务 SSH转发代理:ssh-agent用法详解 SSH隧道:端口转发功能详解 使用ssh-agent之前 使用ssh公钥认证的方式可以免去ssh客户端(如 ...

  6. 【WebAPI No.3】API的访问控制IdentityServer4

    介绍: IdentityServer是一个OpenID Connect提供者 - 它实现了OpenID Connect和OAuth 2.0协议.是一种向客户发放安全令牌的软件. 官网给出的功能解释是: ...

  7. SpringMVC页面向Controller传参

    关于SpringMVC页面向Controller传参的问题,看了网上不少帖子,大多总结为以下几类: 1.直接把页面表单中相关元素的name属性对应的值作为Controller方法中的形参. 这个应该是 ...

  8. react 函数子组件(Function ad Child Component)

    今天学习了react中的函数子组件的概念,然后在工作中得到了实际应用,很开心,那么好记性不如烂笔头,开始喽~ 函数子组件(FaCC )与高阶组件做的事情很相似, 都是对原来的组件进行了加强,类似装饰者 ...

  9. 记录自己使用GitHub的点点滴滴

    前言 现在大多数开发者都有自己的GitHub账号,很多公司也会以是否有GitHub作为一项筛选简历以及人才的选项了,可见拥有一个GitHub账号的重要性,本文就从最基本的GitHub账号的注册到基本的 ...

  10. TextView图文混排

    大家都知道,textView有一个setCompoundDrawables的方法来设置上下左右位置的图标,当然,也可以在xml布局文件中设置,然而问题来了,假如我们把图标放在左边,当我们让TextVi ...