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 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
- 但如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少,而过去 15 分钟内却有很大的负载。
- 反过来,如果 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 包。
3.1.2 工具介绍
- stress包:是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
- stress-ng:stress的进阶版,更加强大,弥补的使用stress包测试IO时,%iowait无法升高的问题。
- sysstat包:包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpstat 和 pidstat。
- mpstat:是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。
- pidstat:是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。
- iotop: 是一个类似 top 的工具,用来显示实时的磁盘活动。
3.1.3 注意事项
每个场景都需要开三个终端,登录到同一台 Linux 机器中。
3.1.4 工具包安装与升级
3.1.4.1 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)
3.1.4.2 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
3.1.4.3 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 个进程(stress)在争抢 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%