mportant; font-size: 1rem; word-break: break-all; color: rgb(51, 51, 51); line-height: 1.74; max-width: 100%;">

  一、iostat基础

  %iowait并不能反应磁盘瓶颈

  1、安装iostat

  iostat的包名叫sysstat

yum install sysstat  -y1.

  2、iowait实际测量的是cpu时间:

%iowait = (cpu idle time)/(all cpu time)1.

  说明:高速cpu会造成很高的iowait值,但这并不代表磁盘是系统的瓶颈。唯一能说明磁盘是系统瓶颈的方法,就是很高的read/write时间,一般来说超过20ms,就代表了不太正常的磁盘性能。为什么是20ms呢?一般来说,一次读写就是一次寻到+一次旋转延迟+数据传输的时间。由于,现代硬盘数据传输就是几微秒或者几十微秒的事情,远远小于寻道时间2~20ms和旋转延迟4~8ms,所以只计算这两个时间就差不多了,也就是15~20ms。只要大于20ms,就必须考虑是否交给磁盘读写的次数太多,导致磁盘性能降低了。

  二、iostat来对linux硬盘IO性能进行了解

  1、iostat分析

  使用其工具filemon来检测磁盘每次读写平均耗时。在Linux下,可以通过iostat命令还查看磁盘性能。其中的svctm一项,反应了磁盘的负载情况,如果该项大于15ms,并且util%接近100%,那就说明,磁盘现在是整个系统性能的瓶颈了。

# iostat -x 1
Linux 3.10.0-514.26.2.el7.x86_64 (v01-ops-es03)     2018年06月27日     _x86_64_    (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          15.10    0.00    5.72   18.54    0.00   60.64

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.24     0.40    0.15    0.15     2.64     2.65    35.08     0.00    1.55    2.94    0.20   0.69   0.02
sdb               0.00     0.10    0.06    0.05     0.54     0.69    22.27     0.00    1.68    3.08    0.07   0.42   0.001.2.3.4.5.6.7.8.9.
  • rrqm/s:          每秒进行 merge 的读操作数目。即 delta(rmerge)/s

  • wrqm/s:         每秒进行 merge 的写操作数目。即 delta(wmerge)/s

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

  • w/s:            每秒完成的写 I/O 设备次数。即 delta(wio)/s

  • rsec/s:         每秒读扇区数。即 delta(rsect)/s

  • wsec/s:         每秒写扇区数。即 delta(wsect)/s

  • rkB/s:          每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。(需要计算)

  • wkB/s:          每秒写K字节数。是 wsect/s 的一半。(需要计算)

  • avgrq-sz:       平均每次设备I/O操作的数据大小 (扇区)。delta(rsect+wsect)/delta(rio+wio)

  • avgqu-sz:       平均I/O队列长度。即 delta(aveq)/s/1000 (因为aveq的单位为毫秒)。

  • await:          平均每次设备I/O操作的等待时间 (毫秒)。即 delta(ruse+wuse)/delta(rio+wio)

  • svctm:          平均每次设备I/O操作的服务时间 (毫秒)。即 delta(use)/delta(rio+wio)

  • %util:          一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的。即 delta(use)/s/1000 (因为use的单位为毫秒)

  如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。

  idle小于70% IO压力就较大了,一般读取速度有较多的wait。

  同时可以结合vmstat 查看查看b参数(等待资源的进程数)和wa参数(IO等待所占用的CPU时间的百分比,高过30%时IO压力高)

  await 的参数也要多和 svctm 来参考。差的过高就一定有 IO 的问题。

  avgqu-sz 也是个做 IO 调优时需要注意的地方,这个就是直接每次操作的数据的大小,如果次数多,但数据拿的小的话,其实 IO 也会很小.如果数据拿的大,才IO 的数据会高。也可以通过 avgqu-sz × ( r/s or w/s ) = rsec/s or wsec/s.也就是讲,读定速度是这个来决定的。

  另外还可以参考

  svctm 一般要小于 await (因为同时等待的请求的等待时间被重复计算了),svctm 的大小一般和磁盘性能有关,CPU/内存的负荷也会对其有影响,请求过多也会间接导致 svctm 的增加。await 的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式。如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明 I/O 队列太长,应用得到的响应时间变慢,如果响应时间超过了用户可以容许的范围,这时可以考虑更换更快的磁盘,调整内核 elevator 算法,优化应用,或者升级 CPU。

  队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 洪水。

  别人一个不错的例子(I/O 系统 vs. 超市排队)

  举一个例子,我们在超市排队 checkout 时,怎么决定该去哪个交款台呢? 首当是看排的队人数,5个人总比20人要快吧? 除了数人头,我们也常常看看前面人购买的东西多少,如果前面有个采购了一星期食品的大妈,那么可以考虑换个队排了。还有就是收银员的速度了,如果碰上了连 钱都点不清楚的新手,那就有的等了。另外,时机也很重要,可能 5 分钟前还人满为患的收款台,现在已是人去楼空,这时候交款可是很爽啊,当然,前提是那过去的 5 分钟里所做的事情比排队要有意义 (不过我还没发现什么事情比排队还无聊的)。

  2、I/O 系统也和超市排队有很多类似之处:

  • r/s+w/s 类似于交款人的总数

  • 平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数

  • 平均服务时间(svctm)类似于收银员的收款速度

  • 平均等待时间(await)类似于平均每人的等待时间

  • 平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少

  • I/O 操作率 (%util)类似于收款台前有人排队的时间比例。

  • 我们可以根据这些数据分析出 I/O 请求的模式,以及 I/O 的速度和响应时间。

  下面是别人写的这个参数输出的分析

# iostat -x 1
Linux 3.10.0-514.26.2.el7.x86_64 (v01-ops-es03)     2018年06月27日     _x86_64_    (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          15.10    0.00    5.72   18.54    0.00   60.64

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.24     0.40    0.15    0.15     2.64     2.65    35.08     0.00    1.55    2.94    0.20   0.69   0.02
sdb               0.00     0.10    0.06    0.05     0.54     0.69    22.27     0.00    1.68    3.08    0.07   0.42   0.001.2.3.4.5.6.7.8.9.

 

  上面的 iostat 输出表明秒有 28.57 次设备 I/O 操作: 总IO(io)/s = r/s(读) +w/s(写) = 1.02+27.55 = 28.57 (次/秒) 其中写操作占了主体 (w:r = 27:1)。

  • 平均每次设备 I/O 操作只需要 5ms 就可以完成,但每个 I/O 请求却需要等上 78ms,为什么? 因为发出的 I/O 请求太多 (每秒钟约 29 个),假设这些请求是同时发出的,那么平均等待时间可以这样计算:

  • 平均等待时间 = 单个 I/O 服务时间 * ( 1 + 2 + … + 请求总数-1) / 请求总数

  • 应用到上面的例子: 平均等待时间 = 5ms * (1+2+…+28)/29 = 70ms,和 iostat 给出的78ms 的平均等待时间很接近。这反过来表明 I/O 是同时发起的。

  • 每秒发出的 I/O 请求很多 (约 29 个),平均队列却不长 (只有 2 个 左右),这表明这 29 个请求的到来并不均匀,大部分时间 I/O 是空闲的。

  • 一秒中有 14.29% 的时间 I/O 队列中是有请求的,也就是说,85.71% 的时间里 I/O 系统无事可做,所有 29 个 I/O 请求都在142毫秒之内处理掉了。

  delta(ruse+wuse)/delta(io) = await = 78.21 => delta(ruse+wuse)/s =78.21 * delta(io)/s = 78.21*28.57 = 2232.8,表明每秒内的I/O请求总共需要等待2232.8ms。所以平均队列长度应为 2232.8ms/1000ms = 2.23,而 iostat 给出的平均队列长度 (avgqu-sz) 却为 22.35,为什么?! 因为 iostat 中有 bug,avgqu-sz 值应为 2.23,而不是 22.35

二、Linux iowait过高问题的查找及解决

  Linux 有许多可用来查找问题的简单工具,也有许多是更高级的

  I/O Wait 就是一个需要使用高级的工具来debug的问题,当然也有许多基本工具的高级用法。I/O wait的问题难以定位的原因是因为我们有很多工具可以告诉你说I/O 受限了,但是并没有告诉你具体是那个进程引起的(哪些进程们)

  一、确认是否是I/O问题导致系统缓慢

  确认是否是I/O导致的系统缓慢我们可以使用多个命令,但是,最简单的是unix的命令 top

  二、查找哪块磁盘正在被写入

  上边的top命令从一个整体上说明了I/O wait,但是并没有说明是哪块磁盘影响的,想知道是哪块磁盘引发的问题,我们用到了另外一个命令 iostat 命令

[root@localhost ~]# iostat -x 2 5 Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     2017年03月03日     _x86_64_    (1 CPU) avg-cpu:  %user   %nice %system %iowait  %steal   %idle            0.34    0.00    0.31    0.01    0.00   99.33 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.05    1.16    0.17    39.00    17.38    84.60     0.00    2.17    0.87   11.14   0.65   111.41 scd0              0.00     0.00    0.00    0.00     0.00     0.00     8.00     0.00    0.64    0.64    0.00   0.64   0.00 dm-0              0.00     0.00    1.10    0.20    37.85    17.21    84.71     0.00    2.43    0.90   10.88   0.66   0.09 dm-1              0.00     0.00    0.01    0.02     0.07     0.08     9.70     0.00    1.42    0.27    2.05   0.09   0.001.2.3.4.5.6.7.8.9.10.11.
iowait 过高问题的查找及解决linux_IO

  上边的例子中,iostat 会每2秒更新一次,一共打印5次信息, -x 的选项是打印出扩展信息

  第一个iostat 报告会打印出系统最后一次启动后的统计信息,这也就是说,在多数情况下,第一个打印出来的信息应该被忽略,剩下的报告,都是基于上一次间隔的时间。举例子来说,这个命令会打印5次,第二次的报告是从第一次报告出来一个后的统计信息,第三次是基于第二次 ,依次类推

  在上面的例子中,sda的%utilized 是111.41%,这个很好的说明了有进程正在写入到sda磁盘中。

  除了%utilized 外,我们可以得到更丰富的资源从iostat,例如每毫秒读写请求(rrqm/s & wrqm/s)),每秒读写的((r/s & w/s),当然还有更多。在上边的例子中,我们的项目看起来正在读写非常多的信息。这个对我们查找相应的进程非常有用

  三、查找引起高I/O wait 对应的进程 

  最简单的方式来发现罪魁祸首是使用命令iotop,通过查看iotop的统计信息,我们可以很容易的指导sshd就是罪魁祸首

  虽然iotop是一个非常强大的工具,并且使用简单,但是它并不是默认安装在所有的linux操作系统中。并且我个人倾向不要太依赖那些默认没有安装的命令。一个系统管理员可能会发现他无法立即安装额外的除默认程序之外的软件,除非等到后边的维护的时间。

  四、查找哪个文件引起的I/Owait

 lsof 命令可以展示一个进程打开的所有文件,或者打开一个文件的所有进程。从这个列表中,我们可以找到具体是什么文件被写入,根据文件的大小和/proc中io文件的具体数据

我们可以使用-p <pid>的方式来减少输出,pid是具体的进程 

[root@localhost ~]# lsof -p 1028 COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME sshd    1028 root  cwd    DIR  253,0      233      64 / sshd    1028 root  rtd    DIR  253,0      233      64 / sshd    1028 root  txt    REG  253,0   819640 2393730 /usr/sbin/sshd sshd    1028 root  mem    REG  253,0    61752  180464 /usr/lib64/libnss_files-2.17.so sshd    1028 root  mem    REG  253,0    43928  180476 /usr/lib64/librt-2.17.so sshd    1028 root  mem    REG  253,0    15688  269136 /usr/lib64/libkeyutils.so.1.5 sshd    1028 root  mem    REG  253,0    62744  482870 /usr/lib64/libkrb5support.so.0.1 sshd    1028 root  mem    REG  253,0    11384  180425 /usr/lib64/libfreebl3.so sshd    1028 root  mem    REG  253,0   143352  180472 /usr/lib64/libpthread-2.17.so sshd    1028 root  mem    REG  253,0   251784  202440 /usr/lib64/libnspr4.so sshd    1028 root  mem    REG  253,0    20016  202441 /usr/lib64/libplc4.so sshd    1028 root  mem    REG  253,0    15768  202442 /usr/lib64/libplds4.so sshd    1028 root  mem    REG  253,0   182056  202443 /usr/lib64/libnssutil3.so sshd    1028 root  mem    REG  253,0  1220240  650074 /usr/lib64/libnss3.so sshd    1028 root  mem    REG  253,0   164048  650076 /usr/lib64/libsmime3.so sshd    1028 root  mem    REG  253,0   276752  650077 /usr/lib64/libssl3.so sshd    1028 root  mem    REG  253,0   121296  269112 /usr/lib64/libsasl2.so.3.0.0 sshd    1028 root  mem    REG  253,0   398264  202404 /usr/lib64/libpcre.so.1.2.0 sshd    1028 root  mem    REG  253,0  2116736  180446 /usr/lib64/libc-2.17.so sshd    1028 root  mem    REG  253,0    15848  202439 /usr/lib64/libcom_err.so.2.1 sshd    1028 root  mem    REG  253,0   202568  482862 /usr/lib64/libk5crypto.so.3.1 sshd    1028 root  mem    REG  253,0   959008  482868 /usr/lib64/libkrb5.so.3.3 sshd    1028 root  mem    REG  253,0   324888  482858 /usr/lib64/libgssapi_krb5.so.2.2 sshd    1028 root  mem    REG  253,0   110632  180474 /usr/lib64/libresolv-2.17.so sshd    1028 root  mem    REG  253,0    40640  180450 /usr/lib64/libcrypt-2.17.so sshd    1028 root  mem    REG  253,0   113152  180456 /usr/lib64/libnsl-2.17.so sshd    1028 root  mem    REG  253,0    90664  202424 /usr/lib64/libz.so.1.2.7 sshd    1028 root  mem    REG  253,0    14432  186432 /usr/lib64/libutil-2.17.so sshd    1028 root  mem    REG  253,0    61872  766946 /usr/lib64/liblber-2.4.so.2.10.3 sshd    1028 root  mem    REG  253,0   344280  766948 /usr/lib64/libldap-2.4.so.2.10.3 sshd    1028 root  mem    REG  253,0    19344  180452 /usr/lib64/libdl-2.17.so sshd    1028 root  mem    REG  253,0  2025472  482880 /usr/lib64/libcrypto.so.1.0.1e sshd    1028 root  mem    REG  253,0    23968  202508 /usr/lib64/libcap-ng.so.0.0.0 sshd    1028 root  mem    REG  253,0   155744  202421 /usr/lib64/libselinux.so.1 sshd    1028 root  mem    REG  253,0    61672  539049 /usr/lib64/libpam.so.0.83.1 sshd    1028 root  mem    REG  253,0   122936  202512 /usr/lib64/libaudit.so.1.0.0 sshd    1028 root  mem    REG  253,0    42520  298848 /usr/lib64/libwrap.so.0.7.6 sshd    1028 root  mem    REG  253,0    11328  568388 /usr/lib64/libfipscheck.so.1.2.1 sshd    1028 root  mem    REG  253,0   155064  180439 /usr/lib64/ld-2.17.so sshd    1028 root    0u   CHR    1,3      0t0    5930 /dev/null sshd    1028 root    1u   CHR    1,3      0t0    5930 /dev/null sshd    1028 root    2u   CHR    1,3      0t0    5930 /dev/null sshd    1028 root    3u  IPv4  21185      0t0     TCP *:ssh (LISTEN) sshd    1028 root    4u  IPv6  21194      0t0     TCP *:ssh (LISTEN)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.

  从上面的命令结果来看,我们可以确定/tmp 是我们环境的逻辑磁盘的根目录

  过pvdisplay我们能看到/dev/sda2其实就是我们用来创建逻辑磁盘的具体磁盘。通过以上的信息我们可以放心的说lsof的结果就是我们要查找的文件