1. 平均负载

1.1 什么是平均负载

平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。

1.1.1 什么是可运行状态

指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 top 命令看到的,处于 R 状态(Running 或 Runnable)的进程。

1.1.2 什么是不可中断状态

不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 top 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。


比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。

1.1.3 总结

既然平均的是活跃进程数,那么最理想的,就是每个 CPU 上都刚好运行着一个进程,这样每个 CPU 都得到了充分利用。比如当平均负载为 2 时,意味着什么呢?

  • 在只有 2 个 CPU 的系统上,意味着所有的 CPU 都刚好被完全占用。
  • 在 4 个 CPU 的系统上,意味着 CPU 有 50% 的空闲。
  • 而在只有 1 个 CPU 的系统中,则意味着有一半的进程竞争不到 CPU。

1.2 平均负载为多少时合理

平均负载最理想的情况是等于 CPU 个数。

1.2.1 查看系统cpu逻辑个数
[root@test-apollo ~]# grep 'model name' /proc/cpuinfo | wc -l # 这里为4个CPU
4

# 用top也可以 但是cpu如果很多的时候,top可能显示不完全
top - 17:27:31 up 3 days,  2:00,  2 users,  load average: 0.06, 0.03, 0.05
Tasks: 189 total,   1 running, 188 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.3 us,  0.7 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.3 us,  0.7 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

1.3 分析平均负载的三个时间段

  1. 如果 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
  2. 但如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少,而过去 15 分钟内却有很大的负载。
  3. 反过来,如果 1 分钟的值远大于 15 分钟的值,就说明最近 1 分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦 1 分钟的平均负载接近或超过了 CPU 的个数,就意味着系统正在发生过载的问题,这时就得分析调查是哪里导致的问题,并要想办法优化了。

1.4 如何关注生产的平均负载

当平均负载高于 CPU 数量 70% 的时候,就应该分析排查负载高的问题了。

因为一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能。


但 70% 这个数字并不是绝对的,最推荐的方法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化趋势。当发现负载有明显升高趋势时,比如说负载翻倍了,再去做分析和调查。

2. 平均负载与 CPU 使用率的区别

2.1 平均负载

平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。

2.2 CPU 使用率

CPU 使用率指单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:

  • CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
  • I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
  • 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。

3. 平均负载案例分析

3.1 使用工具及系统

3.1.1 系统、配置及使用的软件

系统:CentOS 7(linux都可以)

工具:iostat、mpstat、pidstat等

机器配置:2 CPU,8GB 内存。

安装包:stress、sysstat、stress-ng包。

3.1.2 工具介绍
  1. stress包:是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
  2. stress-ng:stress的进阶版,更加强大,弥补的使用stress包测试IO时,%iowait无法升高的问题。
  3. sysstat包:包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpstat 和 pidstat。
  4. mpstat:是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。
  5. pidstat:是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。
  6. iotop: 是一个类似 top 的工具,用来显示实时的磁盘活动。
3.1.3 注意事项

每个场景都需要开三个终端,登录到同一台 Linux 机器中。

3.1.4 工具包安装与升级

sysstat包升级

# 由于CentOS 7 自带的sysstat包版本太低,导致pidstat输出中没有%wait,升级到11.5.5版本以后就可以看到。
# 官网地址:http://sebastien.godard.pagesperso-orange.fr。
# 下载最新稳定版本即可。
[root@test-apollo ~]# wget http://pagesperso-orange.fr/sebastien.godard/sysstat-12.4.5.tar.xz
[root@test-apollo ~]# rpm -e --nodeps sysstat
[root@test-apollo ~]# yum -y install gcc gcc-c++
[root@test-apollo ~]# tar Jxf sysstat-12.4.5.tar.xz
[root@test-apollo ~]# cd sysstat-12.4.5/
[root@test-apollo sysstat-12.4.5]# ./configure --prefix=/usr
[root@test-apollo sysstat-12.4.5]# make install
[root@test-apollo ~]# pidstat -V
sysstat version 12.4.5
(C) Sebastien Godard (sysstat <at> orange.fr)

CPU性能篇-Linux系统平均负载高问题排查-Day 01_cpu

stress-ng包安装

在虚拟机测试过程中使用stress,会导致iowait无法升高,因为案例中stress使用的是 sync() 系统调用,它的作用是刷新缓冲区内存到磁盘中。对于新安装的虚拟机,缓冲区可能比较小,无法产生大的IO压力,这样大部分就都是系统调用的消耗了。

解决办法:使用stress的下一代stress-ng,它支持更丰富的选项,比如 stress-ng -i 1 --hdd 1 --timeout 600(--hdd表示读写临时文件)。

[root@test-apollo ~]# yum -y install stress-ng

stress包安装

[root@test-apollo ~]# yum -y install stress

3.2 场景一:CPU 密集型进程

3.2.1 在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景
[root@test-apollo ~]# stress --cpu 1 --timeout 600
stress: info: [1630] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
3.2.2 在第二个终端运行 uptime 查看平均负载的变化情况
[root@test-apollo ~]# watch -d uptime # -d, 参数表示高亮显示变化的区域
……省略部分输出
17:58:42 up 8 min,  3 users,  load average: 1.22, 0.76, 0.35 # 1分钟的负载,会慢慢变成1或者超过
3.2.3 在第三个终端运行 mpstat 查看 CPU 使用率的变化情况

从终端三中可以看到,正好有一个 CPU 的使用率为 100%,但它的 iowait 只有 0。这说明,平均负载的升高正是由于 CPU 使用率为 100% 。

[root@test-apollo ~]# mpstat -P ALL 5 # -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据
Linux 3.10.0-1062.el7.x86_64 (test-apollo)      08/08/2022      _x86_64_        (2 CPU)

05:59:35 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
05:59:40 PM  all   50.20    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00   49.60
05:59:40 PM    0    0.20    0.00    0.40    0.00    0.00    0.00    0.00    0.00    0.00   99.40
05:59:40 PM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
3.2.4 用 pidstat 来查询使用cpu100%的进程
[root@test-apollo ~]# pidstat -u 5 1 # 间隔5秒后输出一组数据
Linux 3.10.0-1062.el7.x86_64 (test-apollo)      08/09/2022      _x86_64_        (2 CPU)

11:30:46 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:30:51 AM     0      3757  100.00    0.00    0.00    0.00  100.00     0  stress  # 从这里可以明显看到,stress 进程的 CPU 使用率为 100%。
11:30:51 AM     0      3826    0.00    0.20    0.00    0.00    0.20     1  pidstat

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0      3757  100.00    0.00    0.00    0.00  100.00     -  stress
Average:        0      3826    0.00    0.20    0.00    0.00    0.20     -  pidstat

3.3 场景二:I/O 密集型进程

3.3.1 模拟I/O 压力

首先还是运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync

[root@test-apollo ~]# stress-ng -i 1 --hdd 1 --timeout 600
stress-ng: info:  [3454] dispatching hogs: 1 hdd, 1 io
3.3.2 查看平均负载

在第二个终端运行 uptime 查看平均负载的变化情况

[root@test-apollo ~]# watch -d uptime
……省略部分输出
18:08:50 up 18 min,  3 users,  load average: 1.13, 0.92, 0.64 # 1分钟的负载会慢慢变成1甚至超过
3.3.3 查看cpu使用率

第三个终端运行 mpstat 查看 CPU 使用率的变化情况

[root@test-apollo ~]# mpstat -P ALL 5 1 # 从下图可以看到,磁盘IO等待已经%97.8了
Linux 3.10.0-1062.el7.x86_64 (test-apollo)      08/09/2022      _x86_64_        (2 CPU)

10:17:11 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
10:17:16 AM  all    0.10    0.00    0.90   49.05    0.00    0.00    0.00    0.00    0.00   49.95
10:17:16 AM    0    0.20    0.00    1.80   97.80    0.00    0.20    0.00    0.00    0.00    0.00
10:17:16 AM    1    0.20    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.80

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
Average:     all    0.10    0.00    0.90   49.05    0.00    0.00    0.00    0.00    0.00   49.95
Average:       0    0.20    0.00    1.80   97.80    0.00    0.20    0.00    0.00    0.00    0.00
Average:       1    0.20    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.80

# 从这里可以看到,1 分钟的平均负载会慢慢增加到 1.13,其中 iowait 高达 97.80%。这说明,平均负载的升高是由于 iowait 的升高。
3.3.4 查找导致负载变高的进程
[root@test-apollo ~]# pidstat -u 5 1 # 可以看到 负载升高还是由stress-ng造成的
Linux 3.10.0-1062.el7.x86_64 (test-apollo)      08/09/2022      _x86_64_        (2 CPU)

11:33:53 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:33:58 AM     0         9    0.00    0.20    0.00    1.79    0.20     0  rcu_sched
11:33:58 AM     0       507    0.00    0.20    0.00    0.00    0.20     1  kworker/1:1H
11:33:58 AM     0      3819    0.00    0.40    0.00    0.60    0.40     1  kworker/1:1
11:33:58 AM     0      3825    0.00    0.20    0.00    0.00    0.20     0  kworker/0:0
11:33:58 AM     0      3828    0.40   24.90    0.00    0.20   25.30     0  stress-ng-hdd
11:33:58 AM     0      3829    0.00   11.16    0.00    1.79   11.16     1  stress-ng-io
11:33:58 AM     0      3830    0.00    7.37    0.00    1.20    7.37     1  kworker/u4:0
11:33:58 AM     0      3924    0.00    0.40    0.00    0.00    0.40     0  pidstat

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0         9    0.00    0.20    0.00    1.79    0.20     -  rcu_sched
Average:        0       507    0.00    0.20    0.00    0.00    0.20     -  kworker/1:1H
Average:        0      3819    0.00    0.40    0.00    0.60    0.40     -  kworker/1:1
Average:        0      3825    0.00    0.20    0.00    0.00    0.20     -  kworker/0:0
Average:        0      3828    0.40   24.90    0.00    0.20   25.30     -  stress-ng-hdd
Average:        0      3829    0.00   11.16    0.00    1.79   11.16     -  stress-ng-io
Average:        0      3830    0.00    7.37    0.00    1.20    7.37     -  kworker/u4:0
Average:        0      3924    0.00    0.40    0.00    0.00    0.40     -  pidstat

3.4 场景三:大量进程的场景

当系统中运行进程超出 CPU 运行能力时,就会出现等待 CPU 的进程。

3.4.1 使用 stress模拟 8 个进程
[root@test-apollo ~]# stress -c 8 --timeout 600
stress: info: [4544] dispatching hogs: 8 cpu, 0 io, 0 vm, 0 hdd
3.4.2 查看系统负载

由于系统只有 2 个 CPU,明显比 8 个进程要少得多,因而,系统的 CPU 处于严重过载状态,平均负载高达 6.85

[root@test-apollo ~]# uptime
 10:32:36 up 16:42,  4 users,  load average: 6.85, 3.79, 2.42
3.4.3 查看进程

可以看出,8 个进程在争抢 2 个 CPU,每个进程等待 CPU 的时间(也就是代码块中的 %wait 列)高达 75%。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。

[root@test-apollo ~]# pidstat -u 5 1
Linux 3.10.0-1062.el7.x86_64 (test-apollo)      08/09/2022      _x86_64_        (2 CPU)

11:35:34 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:35:39 AM     0      3996   24.95    0.00    0.00   74.85   24.95     1  stress
11:35:39 AM     0      3997   24.95    0.00    0.00   75.25   24.95     0  stress
11:35:39 AM     0      3998   24.95    0.00    0.00   75.25   24.95     0  stress
11:35:39 AM     0      3999   24.95    0.00    0.00   75.25   24.95     0  stress
11:35:39 AM     0      4000   24.95    0.00    0.00   74.85   24.95     1  stress
11:35:39 AM     0      4001   24.95    0.00    0.00   75.05   24.95     1  stress
11:35:39 AM     0      4002   24.75    0.00    0.00   74.45   24.75     0  stress
11:35:39 AM     0      4003   24.95    0.00    0.00   75.25   24.95     1  stress
11:35:39 AM     0      4006    0.00    0.20    0.00    0.00    0.20     0  pidstat

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0      3996   24.95    0.00    0.00   74.85   24.95     -  stress
Average:        0      3997   24.95    0.00    0.00   75.25   24.95     -  stress
Average:        0      3998   24.95    0.00    0.00   75.25   24.95     -  stress
Average:        0      3999   24.95    0.00    0.00   75.25   24.95     -  stress
Average:        0      4000   24.95    0.00    0.00   74.85   24.95     -  stress
Average:        0      4001   24.95    0.00    0.00   75.05   24.95     -  stress
Average:        0      4002   24.75    0.00    0.00   74.45   24.75     -  stress
Average:        0      4003   24.95    0.00    0.00   75.25   24.95     -  stress
Average:        0      4006    0.00    0.20    0.00    0.00    0.20     -  pidstat

4. 总结平均负载

平均负载提供了一个快速查看系统整体性能的手段,反映了整体的负载情况。但只看平均负载本身,我们并不能直接发现,到底是哪里出现了瓶颈。所以,在理解平均负载时,也要注意:

  • 平均负载高有可能是 CPU 密集型进程导致的;
  • 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
  • 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
  • 当发现负载高的时候,可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。

5. 使用百分比公式

(1.73-1)/1*100%=73%