哈喽大家好,我是咸鱼。
我们在使用 top
命令来查看 Linux 系统整体 CPU 使用情况的时候,往往看的是下面这一列:
bash
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 68.0 wa, 0.0 hi, 0.0 si, 0.0 st
其中,man 手册解释 wa
表示 CPU 在等待 I/O 操作(iowait)的时间百分比。
上面输出显示:CPU 有 68% 的时间消耗在等待 I/O 操作完成。按照也就是说有 68% 的 CPU 时间被浪费掉了?可是 Linux 会让 CPU 宝贵的性能白白浪费在耗时的 I/O 等待上吗?CPU 在 iowait 状态的时候能执行其他任务吗?
实际上当 CPU 处于 iowait 状态时,理论上也应该被视为处于 idle (空闲)状态,那 iowait 和 idle 之间有什么联系呢?
今天我们就来解开这些疑惑,来看看 iowait 到底是什么。
参考文章:
bash
https://www.kawabangga.com/posts/5903
https://blog.popkx.com/linux系统top命令中的iowait究竟是什么意思/
https://www.linfo.org/process_state.html
https://blog.pregos.info/wp-content/uploads/2010/09/iowait.txt
进程和 CPU 状态
我们首先要搞清楚进程的状态和 CPU 状态。
进程可以分为下面几种状态:
- R:可执行状态(
runnable
),表示进程正在被 CPU 执行或者处在 CPU 队列中等待分配 CPU 时间片。 - S:可中断睡眠状态(
interrupted sleep
),表示进程处于睡眠状态,当特定条件或者信号到达时,就会被唤醒,状态也由 S 变成 R。 - D:不可中断睡眠状态(
uninterrupted sleep
),跟状态 S 类似,只是进程在接收到信号时不会被唤醒。这类状态的进程一般在等待 I/O 结束。 - Z:僵尸状态(
zombie
),表示进程已经终止(死透了),但父进程还没有发出wait4()
系统调用去读取它的结束信息。(可以理解为进程死【终止】后 父进程要给它收尸【获取该进程的终止状态】) - T:暂停状态(
stopped
),表示进程已经暂停(还没死透),是可以恢复的(比如我们给进程发送 SIGSTOP 或者按 CTRL+Z,就可以将进程置为暂停状态,可以通过 bg/fg 命令,或者发送 SIGCONT 信号恢复。)
CPU 一共有四种状态,在任一时刻,CPU 的状态都是四种中的一种。这四种状态是:user,sys,idle,iowait 。比如 sar、top
会用百分比表示 CPU 分别处于这四种状态的时间,这四种状态相加的结果是 100%。
上面提到的 4 种 CPU 状态,其实只有 2 种:
- 工作/忙碌(busy)
- 非工作/空闲(idle)
其中 busy 状态下又分成了:
- user:表示 CPU 目前正在执行用户空间的代码
- system:表示 CPU 目前正在执行内核空间的代码
idle 状态下又分成了:
- idle:系统中没有 R 状态的进程了
- iowait:系统中没有 R 状态的进程但有进程卡在 I/O 上
这里可以看到:iowait 其实可以归类到 idle 状态,本质上表示 CPU 是空闲的,只不过 iowait 表示任务中有等待 I/O 操作完成的时间。
那既然 iowait 也是一种 idle,CPU 在 iowait 状态的时候能执行其他任务吗?下面让我们来看一个例子。
举个栗子
本次例子在双核 CentOS 7 环境下实验。
我们使用 dd
命令模拟高密集 I/O 任务,并且使用 taskset
来为任务指定 CPU
bash
# taskset 后的数字 1 并不是 CPU 的编号,而是一种掩码。
taskset 1 dd if=/dev/sda of=/dev/null bs=1MB
此时通过 top
命令查看 CPU 使用率,能够发现 CPU0 的 wa 项接近 100,这说明 CPU0 几乎所有的时间都花在等待 I/O 操作完成上。
那么,是不是此时 CPU 就没有精力处理其他任务了呢?我们再输入下面这条命令:
bash
taskset 1 sh -c "while true; do true; done"
这条命令是在相同的 CPU 上执行一个死循环,用于模拟计算密集型任务。
可以看到:CPU0 的 wa
降低为 0 了,与此同时 us
和 sy
的时间占比接近 100% 。CPU 在 iowait 状态的时候能执行了其他任务。
但这就说明 dd
命令产生的进程没有阻塞在 I/O 上吗?并不是。
假设有一个进程需要花 70% 的时间等待 I/O 完成,把它放到一个空闲的单 CPU 的系统中,显示的 iowait 是 70%。
但是我在这个系统中增加一个非 I/O 的计算任务,iowait 就变成 0 了。而我们之前的那个进程依然需要花 70% 的时间等待 I/O。
一个是从 CPU 角度来看,一个是从进程的角度来看,iowait 是 CPU 的一个状态,它不是进程的状态。iowait 很低,不能代表进程没有阻塞在 I/O 上。
总结
最后总结一下:
1)不要搞混 CPU 状态和进程的状态。进程有 R、S、D、Z、T,5 种状态;CPU 有 4 种状态:工作(user、system 两种)和空闲(idle、iowait 两种)。
2)iowait 表示 CPU 其实是空闲的,不过 CPU 并不是严格意义上的 "空闲",上面还有等待 I/O 操作的进程在执行。
3)系统 iowait 高:
- 系统存在 I/O 性能问题:系统正在做的工作,大部分时间都是在等待 I/O 了。
- 有进程因为等待 I/O 操作而阻塞,但这并不意味着系统不可以运行其他进程。
4)系统 iowait 低不能说明进程没有阻塞在 I/O 上。因为 CPU 在 iowait 状态的时候能执行其他进程。