一、iostat基础

1.1 安装iostat

yum install sysstat -y

2.2 iowait实际测量的是cpu时间

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

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

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

2.1 iostat分析

在Linux下,可以通过iostat命令还查看磁盘性能。其中的svctm一项,反应了磁盘的负载情况,如果该项大于15ms,并且util%接近100%,那就说明,磁盘现在是整个系统性能的瓶颈了。

# iostat -x 1
Linux 3.10.0-514.26.2.el7.x86_64 (v01-ops-es03)     2023年11月10日     _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
  • 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压力高)

另外还可以参考

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

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

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

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

  • r/s+w/s 类似于交款人的总数
  • 平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数
  • 平均服务时间(svctm)类似于收银员的收款速度
  • 平均等待时间(await)类似于平均每人的等待时间
  • 平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少
  • I/O 操作率 (%util)类似于收款台前有人排队的时间比例。
  • 我们可以根据这些数据分析出 I/O 请求的模式,以及 I/O 的速度和响应时间

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

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

2.3.1 确认是否是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权限

2.3.2 查找哪块磁盘正在被写入

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

[root@localhost ~]# iostat -x 2 5
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     2023年11月10日     _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),当然还有更多。在上边的例子中,我们的项目看起来正在读写非常多的信息。这个对我们查找相应的进程非常有用。

2.3.3 查找引起高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操作系统中。并且我个人倾向不要太依赖那些默认没有安装的命令。一个系统管理员可能会发现他无法立即安装额外的除默认程序之外的软件,除非等到后边的维护的时间。

2.3.4 查找哪个文件引起的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的结果就是我们要查找的文件

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐