kikimo

Linux iowait

本文主要参考 The precise meaning of I/O wait time in Linux

Linux 中 CPU 的使用统计被拆分成多个组成部分, 最常见的如 sys 表示 CPU 在内核态的使用情况,usr CPU 在用户态的使用情况。 iowait 也是其中一种,它表示 CPU 等待 io 操作的时间。 和其他项相比 iowait 有一个非常特殊的地方:

  1. iowait 高的时候,CPU 的使用率也会变高,但此时 CPU 本身并不繁忙
  2. iowait 高的时候表示系统存在 io 瓶颈,但 iowait 低的时候并不代表系统 io 空闲

第一点其实很好理解,iowait 高,表示 CPU 在等待 io 操作,CPU 自己其实正处于休眠状态, 这个时候高 CPU 并不代表 CPU 使用率真的很高。 既然 iowait 高的时候 CPU 本质上是处于休眠状态,此时如果有一个计算密集型的进程需要 CPU 资源, Linux 就可以把进程调度到休眠中的 CPU 上执行, 这会到时该 CPU 的 usr/sys 变高,相应的它的 iowait 值就会降下来了, 所以,当我们看到 iowait 低的时候,并不能得出系统 io 不繁忙的结论。

我们可以通过一些简单的测试来验证以上的观点:

我们通过dd指令来模拟 io 繁忙的情况,并且利用taskset把它调度到 CPU 4 上这执行:

taskset 0x04 dd if=/dev/sdc of=/dev/null bs=4M

通过mpstat观察各个 CPU 的使用情况:

$ mpstat -P ALL 2
...
22时54分34秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
22时54分36秒  all    9.63    0.00    5.32    8.11    0.00    0.19    0.00    0.00    0.00   76.76
22时54分36秒    0   10.45    0.00    4.98    1.00    0.00    0.50    0.00    0.00    0.00   83.08
22时54分36秒    1   11.94    0.00    6.47    0.00    0.00    0.50    0.00    0.00    0.00   81.09
22时54分36秒    2    6.67    0.00    8.21   64.10    0.00    0.51    0.00    0.00    0.00   20.51
22时54分36秒    3   10.20    0.00    2.55    0.00    0.00    0.00    0.00    0.00    0.00   87.24
22时54分36秒    4    8.72    0.00    5.13    0.00    0.00    0.00    0.00    0.00    0.00   86.15
22时54分36秒    5    8.12    0.00    9.14    0.00    0.00    0.00    0.00    0.00    0.00   82.74
22时54分36秒    6   10.71    0.00    3.06    0.00    0.00    0.00    0.00    0.00    0.00   86.22
22时54分36秒    7   10.15    0.00    2.54    0.51    0.00    0.00    0.00    0.00    0.00   86.80

22时54分36秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
22时54分38秒  all   11.12    0.00    5.56    7.39    0.00    0.32    0.00    0.00    0.00   75.62
22时54分38秒    0   12.56    0.00    6.03    0.00    0.00    0.50    0.00    0.00    0.00   80.90
22时54分38秒    1   10.10    0.00   10.61    0.00    0.00    0.51    0.00    0.00    0.00   78.79
22时54分38秒    2    9.18    0.00   10.71   59.18    0.00    0.00    0.00    0.00    0.00   20.92
22时54分38秒    3   13.57    0.00    3.02    0.00    0.00    0.50    0.00    0.00    0.00   82.91
22时54分38秒    4   11.22    0.00    3.06    0.00    0.00    0.51    0.00    0.00    0.00   85.20
22时54分38秒    5   11.00    0.00    4.00    0.00    0.00    0.50    0.00    0.00    0.00   84.50
22时54分38秒    6   10.71    0.00    3.06    0.00    0.00    0.00    0.00    0.00    0.00   86.22
22时54分38秒    7   10.61    0.00    4.04    0.00    0.00    0.00    0.00    0.00    0.00   85.35
...

可以看到 CPU 4 的 iowait 一直上升到 60% 左右。 再来把一个计算密集型的进程调度到 CPU 4 上执行,然后观察 CPU 4 的使用情况:

taskset 0x04 sh -c "while true; do true; done"
...
22时57分42秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
22时57分44秒  all   11.03    0.00    5.36    6.55    0.00    0.25    0.00    0.00    0.00   76.81
22时57分44秒    0    9.50    0.00    5.00    0.00    0.00    0.50    0.00    0.00    0.00   85.00
22时57分44秒    1   10.34    0.00   10.34    0.00    0.00    0.49    0.00    0.00    0.00   78.82
22时57分44秒    2   27.45    0.00   10.78   50.00    0.00    0.49    0.00    0.00    0.00   11.27
22时57分44秒    3    6.06    0.00    5.05    0.00    0.00    0.51    0.00    0.00    0.00   88.38
22时57分44秒    4    6.22    0.00    2.07    0.00    0.00    0.52    0.00    0.00    0.00   91.19
22时57分44秒    5    6.70    0.00    2.58    0.52    0.00    0.00    0.00    0.00    0.00   90.21
22时57分44秒    6   12.00    0.00    2.00    0.50    0.00    0.00    0.00    0.00    0.00   85.50
22时57分44秒    7    9.09    0.00    4.55    0.51    0.00    0.00    0.00    0.00    0.00   85.86

22时57分44秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
22时57分46秒  all   18.50    0.00    4.08    0.13    0.00    0.44    0.00    0.00    0.00   76.87
22时57分46秒    0    8.42    0.00    7.43    0.50    0.00    0.50    0.00    0.00    0.00   83.17
22时57分46秒    1    7.96    0.00    1.99    0.50    0.00    1.00    0.00    0.00    0.00   88.56
22时57分46秒    2   95.98    0.00    4.02    0.00    0.00    0.00    0.00    0.00    0.00    0.00
22时57分46秒    3    7.58    0.00    4.04    0.00    0.00    0.00    0.00    0.00    0.00   88.38
22时57分46秒    4    5.15    0.00    5.67    0.00    0.00    1.03    0.00    0.00    0.00   88.14
22时57分46秒    5    7.46    0.00    2.99    0.00    0.00    0.00    0.00    0.00    0.00   89.55
22时57分46秒    6    7.61    0.00    1.02    0.00    0.00    0.00    0.00    0.00    0.00   91.37
22时57分46秒    7    7.54    0.00    5.03    0.00    0.00    0.00    0.00    0.00    0.00   87.44

22时57分46秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
22时57分48秒  all   17.58    0.00    3.57    0.44    0.00    0.81    0.00    0.00    0.00   77.60
22时57分48秒    0    6.86    0.00    7.84    0.49    0.00    0.98    0.00    0.00    0.00   83.82
22时57分48秒    1   10.05    0.00    2.87    0.48    0.00    1.44    0.00    0.00    0.00   85.17
22时57分48秒    2   93.00    0.00    3.00    0.00    0.00    4.00    0.00    0.00    0.00    0.00
22时57分48秒    3    6.12    0.00    3.57    1.53    0.00    0.00    0.00    0.00    0.00   88.78
22时57分48秒    4    7.46    0.00    3.48    1.00    0.00    0.00    0.00    0.00    0.00   88.06
22时57分48秒    5    4.12    0.00    1.55    0.00    0.00    0.00    0.00    0.00    0.00   94.33
22时57分48秒    6    7.54    0.00    2.51    0.50    0.00    0.00    0.00    0.00    0.00   89.45
22时57分48秒    7    5.61    0.00    3.57    0.00    0.00    0.00    0.00    0.00    0.00   90.82

可以看到 iowait 里面降下来了,而 usr 飙到将近 100。所以单纯的观察 iowait 无法对系统的 io 使用情况下结论。 那如何确定系统的 io 使用情况呢?我们可以结合 iostat 来观察:

$ iostat -d 2
...
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
loop0             0.00         0.00         0.00          8          0
sda               1.52       136.33         0.02   13560549       2312
sdb               5.29        42.84        48.49    4261263    4822780
sdc               1.21       553.01         0.00   55006268          0

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
loop0             0.00         0.00         0.00          0          0
sda               0.00         0.00         0.00          0          0
sdb              17.50        72.00         0.00        144          0
sdc             106.50     72704.00         0.00     145408          0

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
loop0             0.00         0.00         0.00          0          0
sda               0.00         0.00         0.00          0          0
sdb              51.50       888.00        30.00       1776         60
sdc             108.50     74240.00         0.00     148480          0

可以很明显的看到 sdc 设备上有大量的读操作。