一、iostat和iowait详细解说-查看磁盘瓶颈
一、iostat基础
%iowait并不能反应磁盘瓶颈
1、安装iostat
iostat的包名叫sysstat
yum install sysstat -y
2、iowait实际测量的是cpu时间:
%iowait = (cpu idle time)/(all cpu time)
说明:高速cpu会造成很高的iowait值,但这并不代表磁盘是系统的瓶颈。唯一能说明磁盘是系统瓶颈的方法,就是很高的read/write时间,一般来说超过20ms,就代表了不太正常的磁盘性能。为什么是20ms呢?一般来说,一次读写就是一次寻到+一次旋转延迟+数据传输的时间。由于,现代硬盘数据传输就是几微秒或者几十微秒的事情,远远小于寻道时间220ms和旋转延迟48ms,所以只计算这两个时间就差不多了,也就是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.00
如果 %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 系统也和超市排队有很多类似之处:
下面是别人写的这个参数输出的分析
# 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.00
上面的 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
[root@localhost ~]# top
top - 15:19:26 up 6:10, 4 users, load average: 0.00, 0.01, 0.05
Tasks: 147 total, 1 running, 146 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.3 sy, 0.0 ni, 99.7 id, 96.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 999936 total, 121588 free, 328672 used, 549676 buff/cache
KiB Swap: 2097148 total, 2095792 free, 1356 used. 450460 avail Mem
从Cpu一行我们可以看到浪费在I/O Wait上的CPU百分比;这个数字越高说明越多的CPU资源在等待I/O权限
wa -- iowait
AmountoftimetheCPUhasbeenwaitingfor I/O to complete.
二、查找哪块磁盘正在被写入
上边的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.00
上边的例子中,iostat 会每2秒更新一次,一共打印5次信息, -x 的选项是打印出扩展信息
第一个iostat 报告会打印出系统最后一次启动后的统计信息,这也就是说,在多数情况下,第一个打印出来的信息应该被忽略,剩下的报告,都是基于上一次间隔的时间。举例子来说,这个命令会打印5次,第二次的报告是从第一次报告出来一个后的统计信息,第三次是基于第二次 ,依次类推
在上面的例子中,sda的%utilized 是111.41%,这个很好的说明了有进程正在写入到sda磁盘中。
除了%utilized 外,我们可以得到更丰富的资源从iostat,例如每毫秒读写请求(rrqm/s & wrqm/s)),每秒读写的((r/s & w/s),当然还有更多。在上边的例子中,我们的项目看起来正在读写非常多的信息。这个对我们查找相应的进程非常有用
三、查找引起高I/O wait 对应的进程
[root@localhost ~]# iotop
Total DISK READ : 0.00 B/s | Total DISK WRITE : 0.00 B/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1028 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % sshd
最简单的方式来发现罪魁祸首是使用命令iotop,通过查看iotop的统计信息,我们可以很容易的指导sshd就是罪魁祸首
虽然iotop是一个非常强大的工具,并且使用简单,但是它并不是默认安装在所有的linux操作系统中。并且我个人倾向不要太依赖那些默认没有安装的命令。一个系统管理员可能会发现他无法立即安装额外的除默认程序之外的软件,除非等到后边的维护的时间。
四、查找哪个文件引起的I/Owait
lsof 命令可以展示一个进程打开的所有文件,或者打开一个文件的所有进程。从这个列表中,我们可以找到具体是什么文件被写入,根据文件的大小和/proc中io文件的具体数据
我们可以使用-p 的方式来减少输出,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
为了更深入的确认这些文件被频繁的读写,我们可以通过如下命令来查看
root@localhost ~]# df /tmp
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/mapper/cl-root 17811456 3981928 13829528 23% /
从上面的命令结果来看,我们可以确定/tmp 是我们环境的逻辑磁盘的根目录
[root@localhost ~]# pvdisplay
--- Physical volume ---
PV Name /dev/sda2
VG Name cl
PV Size 19.00 GiB / not usable 3.00 MiB
Allocatable yes (but full)
PE Size 4.00 MiB
Total PE 4863
Free PE 0
Allocated PE 4863
PV UUID 4QfaOy-DNSO-niK1-ayn2-K6AY-WZMy-9Nd2It
过pvdisplay我们能看到/dev/sda2其实就是我们用来创建逻辑磁盘的具体磁盘。通过以上的信息我们可以放心的说lsof的结果就是我们要查找的文件