• 平均负载与 CPU 使用率,到底有啥区别?


    性能优化中,我们经常会关注 CPU 平均负载这个指标。但如果让你来跟我解释一下什么是平均负载,你能说得清楚吗?它跟 CPU 使用率有什么区别?我想可能很多人都数不清楚,今天我们就来盘一盘 CPU 平均负载这个指标!

    平均负载与 CPU 使用率,到底有啥区别?

    Linux 进程状态

    要弄明白 CPU 平均负载,我们还需要从 Linux 进程状态说起。

    在 Linux 源码的 fs/proc/array.c 文件中,其定义了进程的 7 种状态,如下所示:

    1. /*
    2. * The task state array is a strange "bitmap" of
    3. * reasons to sleep. Thus "running" is zeroand
    4. * you can test for combinations of others with
    5. * simple bit tests.
    6. */
    7. static const char * const task_state_array[] = {
    8.   "R (running)",        /*   0 */
    9.   "S (sleeping)",        /*   1 */
    10.   "D (disk sleep)",    /*   2 */
    11.   "T (stopped)",        /*   4 */
    12.   "t (tracing stop)",    /*   8 */
    13.   "X (dead)",        /*  16 */
    14.   "Z (zombie)",        /*  32 */
    15. };

    第一种状态:TASK_RUNNING 可执行状态,缩写 R。

    该状态表示进程可以在 CPU 上运行,即具备运行的条件。但同一时刻可能有多个进程可以运行,但并不代表该进程已经在运行。处于 TASK_RUNNING 的进程会被放入 CPU 的可执行队列中,随后会被进程调度器分配到其中一个 CPU 上 运行。

    很多操作系统教科书将 CPU 上执行的进程定义为 RUNNING 状态,而将可执行但是尚未被调度执行的进程定义为 READY 状态,这两种状态在 Linux 系统下统一为 TASK_RUNNING 状态。

    第二种状态:TASK_INTERRUPTIBLE 可中断的睡眠状态,缩写 S。

    该状态的进程表示因为等待某某时间的发生而被挂起,例如:等待 socket 连接、等待信号量等等。这些进程会被放入对应事件的等待队列中,当这些事件发生时,对应等待队列中的一个或多个进程将被唤醒。

    通过 ps 命令我们可以看到,绝大多数进程都处于 TASK_INTERRUPTIBLE 状态。这是因为由于 CPU 只有那么几个,而进程却动辄几百上千,因此绝大多数进程在某个时刻都是处于睡眠状态的。如果不是绝大多数进程都在睡眠,CPU 是无法响应得过来的。

    第三种状态:TASK_UNINTERRUPTIBLE 不可中断睡眠状态,缩写 D。

    该状态与 TASK_INTERRUPTIBLE 状态类似,进程处于睡眠状态,但唯一不同的点是该进程是不可中断的。不可中断指的并不是 CPU 不响应外部硬件的中断,而是指进程不响应异步信号。

    绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。即你能够通过 kill -15 pid 方式传递异步信号,程序可以做出响应。但有时候你会惊奇地发现,kill -9 竟然杀不死一个正在睡眠的进程了,这时候有可能就是该进程处于不可中断睡眠状态了!

    TASK_UNINTERRUPTIBLE 状态存在的意义就在于:内核的某些处理流程是不能被打断的,例如:在进程对某些硬件进行操作时,如果产生中断的话会导致进程与硬件设备交互被打断,使得设备陷入不可控状态。这种情况下的 TASK_UNINTERRUPTIBLE 状态总是非常短暂的,通过 ps 命令基本上不可能捕捉到。

    第四、五种状态:TASK_STOPPED 暂停状态、TASK_TRACED 状态,缩写 T。

    当我们向进程发送一个 SIGSTOP 信号时,它就会因响应该信号而进入 TASK_STOPPED 状态。除非该进程本身处于 TASK_UNINTERRUPTIBLE 状态而不响应信号)。向进程发送一个 SIGCONT 信号,可以让其从 TASK_STOPPED 状态恢复到 TASK_RUNNING 状态。

    第六种状态:TASK_DEAD - EXIT_ZOMBIE 退出状态,缩写 Z。

    进程退出之后,进程所占有的所有资源将被回收,随后该进程就被成为僵尸进程(Zombie)。一般情况下是子进程先于父进程退出,并且父进程没有调用 wait 或 waitpid 回收子进程。此时子进程即处于僵尸状态。

    第七种状态:TASK_DEAD - EXIT_DEAD 退出状态,缩写 X。

    进程被置于 EXIT_DEAD 退出状态,这意味着接下来的代码立即就会将该进程彻底释放。一般情况下 EXIT_DEAD 状态是非常短暂的,几乎不可能通过 ps 命令捕捉到。

    看完了 Linux 进程的 7 种状态,是不是有点懵了?其实你只需要记住 Linux 有这 7 种状态,其中最重要的是 RUNNING 状态、UNINTERRUPTIBLE 状态就可以了。

    我们总结一下 Linux 的 7 种进程状态:

    • TASK_RUNNING 可执行状态,缩写 R。

    • TASK_INTERRUPTIBLE 可中断的睡眠状态,缩写 S。

    • TASK_UNINTERRUPTIBLE 不可中断睡眠状态,缩写 D。

    • TASK_STOPPED 暂停状态、TASK_TRACED 状态,缩写 T。

    • TASK_DEAD - EXIT_ZOMBIE 退出状态,缩写 Z。

    • TASK_DEAD - EXIT_DEAD 退出状态,缩写 X。

    平均负载的定义

    平均负载的定义是:单位时间内,系统中处于可运行状态和不可中断状态的平均进程数。 这里的可运行状态和不可中断状态,指的就是上文说到的进程状态。从平均负载的定义来看,其与进程所处的状态有关系,因此我们后续分析平均负载的时候,要以该定义为基础去分析。

    对于有 4 核 CPU 的机器,如果一共运行了 4 个进程,那么每个 CPU 都运行了 1 个进程,此时所有的 CPU 都刚好被完全占用。

    而如果只有 2 个进程,那么意味着 CPU 有 50% 的空闲。而如果有 8 个进程,那么意味着 CPU 超载了,平均负载达到了 2,但单位时间内单个 CPU 需要运行 2 个进程。

    我们可以通过读取 /proc/cpuinfo 文件获取系统 CPU 信息,如下所示:

    $ grep 'model name' /proc/cpuinfo | wc -l2
    

    当平均负载比 CPU 个数还多的时候,就表示系统已经出现了负载。一般情况下,负载不超过 70% 的情况下都是正常的。

    很多人都会将 CPU 平均负载与 CPU 使用率搞混,实际上它们有一定关联,但不是同一个东西。

    平均负载是指单位时间内,处于可运行状态和不可中断的进程数。从其定义可以知道,其不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。而 CPU 使用率指的是正在使用 CPU 的进程,由此可见它们两者是不同的。

    如果是 CPU 密集型的进程,因为进程大量使用 CPU,因此平均负载会上升,CPU 使用率会上升。但如果是 I/O 密集型进程,有很多进程在等待 I/O 操作,此时进程处于不可中断状态,因此平均负载会升高,但是 CPU 使用率却不一定很高。

    由此可见,平均负载与 CPU 使用率有一定关联,但并没有绝对的关系。

    如何查看平均负载?

    一般来说,我们可以通过 top 和 uptime 命令来监控服务器的平均负载。

    在服务器命令行输入 top 即可查看到当前系统的负载情况,如下图所示。

    16611630372239

    上图中平均负载的 3 个数值分别代表 1 分钟、5 分钟、15 分钟系统的平均负载情况。通过这三个数值的变化,我们可以知道系统最近一段时间的压力变化趋势。例如:load average: 15.00, 10.75, 3.25 表示过去 1 分钟负载为 15,过去 5 分钟负载为 10.75,过去 15 分钟负载为 3.25,可以看到其平均负载压力是越来越大的。

    top 命令输出的信息非常多,有时候会干扰我们的视野。所以如果你只需要看系统负载情况,那么你可以用 uptime 命令,如下图所示。

    -w438

    uptime 命令只输出了一行信息,非常简洁。

    如果你需要持续地查看平均负载的变化,那么可以用如下命令。该命令会会持续输出最新的负载信息,并高亮变化的部分。

    watch -d uptime
    

    -w499

    总结

    本文首先介绍了 Linux 进程的 7 种状态,分别是:

    • TASK_RUNNING 可执行状态,缩写 R。

    • TASK_INTERRUPTIBLE 可中断的睡眠状态,缩写 S。

    • TASK_UNINTERRUPTIBLE 不可中断睡眠状态,缩写 D。

    • TASK_STOPPED 暂停状态、TASK_TRACED 状态,缩写 T。

    • TASK_DEAD - EXIT_ZOMBIE 退出状态,缩写 Z。

    • TASK_DEAD - EXIT_DEAD 退出状态,缩写 X。

    随后,我们介绍了平均负载指标的定义,即:单位时间内,系统中处于可运行状态和不可中断状态的平均进程数。

    接着,我们将其与 CPU 使用率做了对比,知道两者的区别在于:平均负载不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。而 CPU 使用率指的是正在使用 CPU 的进程,由此可见它们两者是不同的。

    最后,我们介绍了查看平均负载指标的 2 个命令,即 top 和 uptime 命令。如果需要持续关注平均负载的变化,那么可以使用 watch -d uptime 命令持续输出,并高亮变化的部分。

  • 相关阅读:
    CSS其他属性
    WPF入门教程系列二十五——DataGrid使用示例(2)
    Springboot启动流程
    寻找更好的分类模型loss
    基础IO —— Linux
    Fenix — 比 MyBatis 更加强大的 Spring Data JPA 扩展库
    【RP2物联网实战(一)】C/C++&FreeRTOS版
    基于java的移动端自动化测试 - appium-client api -DesiredCapabilities属性有哪些?
    thinkphp6入门(21)-- 如何删除图片、文件
    从GitHub火到头条!这套万人期待的 JAVA 小白成神之路PDF,终于开源了!
  • 原文地址:https://blog.csdn.net/m0_71777195/article/details/126868411