iowait详解

2019-04-26

iowait详解

翻译自https://blog.pregos.info/wp-content/uploads/2010/09/iowait.txt 缘起:https://serverfault.com/questions/12679/can-anyone-explain-precisely-what-iowait-is

So,到底什么是 "iowait"?

一句话总结一下:iowait是CPU处于idle空闲状态,并且至少有1个I/O处在处理中状态的时间百分比.

每个CPU可能处在以下四种状态中的一种:user,sys,idel,iowait;性能测试工具比如vmstat,iostat,sar,都可以把这四种状态以百分比的形式显示出来.sar工具可以通过-P参数显示每个CPU的基础信息,但是其他大部分工具都是显示所有CPU核心的平均值.这四种状态的百分比相加为100%.

这些工具显示的统计信息,是通过内核周期性更新统计出来的.(对于AIX,CPU统计更新周期为每个时钟中断,10毫秒一次).当CPU发生时钟中断,内核会检查CPU是不是处于idle状态.如果不是idle状态,那么内核会判断正在执行的命令是用户态还是内核态,如果是用户态则吧'user'加一,如果是内核态则把'sys'加一.

如果cpu处在idle状态,内核会判断是不是有IO读写正在进行,如果至少有一个IO正在执行,不管是本地磁盘读写还是远程磁盘读写(比如mount的NFS磁盘);如果有,那么'iowait'计数器就会加一.如果没有IO正在进行,'idle'计数器就加一.

当运行性能测试工具,比如vmstat的时候,它读取的就是这四个状态的计数器,然后根据用户指定的时间睡眠几秒,然后在读取一次.然后vmstat会根据两次取值的绝对值,计算出这一段取样时间的变化值.vmstat知道每次时钟滴答都会改变计数器的值,它就可以算出每次时钟滴答内计数器的变化量.举个栗子,如果执行"vmstat 2",vmstat就会每2秒钟对计数器进行一次取样.由于每次时钟循环时间在10ms,所以每秒有100次循环,2s就有200次时钟循环.每个计数器的差值除以循环周期的总统计次数,乘以100就得到了周期内的百分比.

iowait在某些情况下,可以作为衡量系统吞吐能力的一个指标,但是在另外一些情况下,这个数值可能是毫无意义的. 有一些例子来帮助解释一下这个情况.第一个例子,iowait是导致性能原因的直接因素:

Example 1:

假设有一个程序,需要执行一组包含多个任务的事务.每个事务执行的过程中,需要执行10ms计算任务,然后把结果以同步的方式写入磁盘.由于要写入的文件是以同步方式打开的,所以只有当写入的I/O操作全部完成后,写入调用才会返回.假设磁盘系统没有cache缓存,并且每次写入的I/O操作需要20ms.在这种情况下,每次事务操作需要30ms.在1S内(1000ms)这个程序可以完成33次事务(33tps).如果这个程序是在单核心系统(1CPU)上运行的唯一的程序,那么CPU的使用率会是1/3处在忙(busy)状态,剩下的时间等待I/O - 所以是66%的iowait 和 34%的CPU busy.

假设,对I/O系统进行了优化(比如增加了磁盘缓存),每次I/O操作只需要1ms,那么每次事务只需要11ms,那么程序每秒就可以执行90-91次事务了.这种情况下iowait大概在8%.因此更低的iowait时间直接影响了程序的执行能力(吞吐量).

Example 2:

假设系统中有一个正在执行的程序,例如 'dd'程序,每次从磁盘读取4kb的数据.假设dd中的一个函数main()会调用read()方法来读取数据.main函数和read函数都是用户态的函数.read方法是libc.a提供的一个函数,这个函数会调用kread()系统调用,从而进入内核态.kread()会初始化设备并进行一次物理I/O,'dd'程序在此期间会睡眠(sleep)直到物理I/O完成.执行main,read,kread代码需要的时间很短 - 大概只需要50微秒,对于磁盘而言,完成I/O请求大概需要2-20ms,主要取决于磁盘的机械臂寻址的时间.因此,当时钟中断发生时,'dd'程序很可能在睡眠状态,I/O处在执行中的状态.因此,'iowait'计数器会增加.如果I/O在2ms完成,'dd'程序就继续执行下一次读操作.但是对比起来,50微秒要远远少于20ms,当时钟中断发生时,CPU更有可能还是处于idle状态,I/O任务仍然在进行中.因此,'iowait'还会增加.如果执行' sar -P '来统计这个CPU的使用状态,iowait很可能处于97-98%.如果每次I/O需要20ms,那iowait可能会是99-100%.因此尽管I/O wait非常高,但是吞吐量依然比第一个例子中的情况要高10倍左右.

Example 3

假设在同一个CPU上正在执行2个程序.其中一个'dd'负责从磁盘读取数据,另一个程序不会执行I/O操作,但是100%的时间都用来做计算工作.现在,假设I/O系统出现了故障,需要1s才能完成一次物理I/O操作.因此,当'dd'程序处于睡眠状态等待I/O结束时,另一个程序依然可以使用CPU.当时钟中断发生时,总会有一个程序处于用户态或内核态,因此 %idle和%iowait会是0.即便iowait是0,并不意味着就没有I/O问题,因为显然一次I/O执行超过了一秒是肯定有问题的.

Example 4

假设在一个4核CPU的系统上有6个程序在执行.假设有4个程序,花费了70%的时间在等待物理I/O,还有30%时间真正使用了CPU.由于这四个程序需要进入内核态来执行kread系统调用,这就会花费部分比例的时间在内核中;假设有25%的时间是用户态,5%是内核态.

另外,我们假设剩下的两个程序消耗100%的时间全部用来计算,没有I/O请求,所以CPU永远都会100%忙碌.其他4个程序只需要30%的CPU资源,这俩程序就可以使用剩下的CPU资源了.

如果我们执行 'sar -P ALL 1 10',通过每秒执行一次'sar',一共10次,我们能够看到每次执行的结果如下:

cpu    %user    %sys   %wio    %idle
0        50       10     40       0
1        50       10     40       0
2        100      0       0       0 
3        100      0       0       0
-         75      5       20      0

注意一下,CPU使用的分配,75%为user,5%是sys,20%的iowait.如果通过'vmstat'或'iostat'等其他工具,看到的就是所有CPU的平均值.

现在,让我们把同样的负载(同样的6个程序,同样的执行情况)放到另一台有6核CPU(同样的CPU速度和同样的IO系统)的机器上执行.现在,各个程序都可以在独立的一个CPU上执行了,因此CPU的使用情况如下:

cpu    %user    %sys    %wio    %idle
0         25       5      70        0
1         25       5      70        0
2         25       5      70        0
3         25       5      70        0
4        100       0       0        0
5        100       0       0        0
-         50       3      47        0

现在,平均的CPU使用率为50% user,3% sys, 47% iowait.注意一下,同样的负载情况,在另一台机器会导致iowait的值提高了2倍多.

结论

iowait的结果对于衡量I/O性能可能有用,也可能没什么用.但是至少告诉了我们系统能负担更多的计算任务,因为CPU处在iowait状态不代表CPU就不能执行其他进程了;因此,iowait只是另一种idle的状态而已.


Tags: iowait linux