uptime
# uptime root@iZbp14ipzpabr30yllskn4Z
14:37:58 up 403 days, 1:48, 4 users, load average: 0.74, 0.63, 0.60
~
# 而最后三个数字呢,依次则是过去 1 分钟、5 分钟、15 分钟的平均负载(Load Average)。
平均负载
平均负载是指单位时间内,系统处**于可运行状态和不可中断状态**的平均进程数,也就是**平均活跃进程数**,它和 CPU 使用率并没有直接关系。这里我先解释下,可运行状态和不可中断状态这俩词儿。
所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。
不可中断状态实际上是系统对进程和硬件设备的一种保护机制。
既然平均的是活跃进程数,那么最理想的,就是每个 CPU 上都刚好运行着一个进程,这样每个 CPU 都得到了充分利用。比如当平均负载为 2 时,意味着什么呢?
* 在只有 2 个 CPU 的系统上,意味着所有的 CPU 都刚好被完全占用。
* 在 4 个 CPU 的系统上,意味着 CPU 有 50% 的空闲。
* 而在只有 1 个 CPU 的系统中,则意味着有一半的进程竞争不到 CPU。
查看CPU个数
[root@VM-64-25-centos ~]# grep 'model name' /proc/cpuinfo | wc -l
8
[root@VM-64-25-centos ~]#
平均负载为多少时合理
* 如果 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
* 但如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少,而过去 15 分钟内却有很大的负载。
* 反过来,如果 1 分钟的值远大于 15 分钟的值,就说明最近 1 分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦 1 分钟的平均负载接近或超过了 CPU 的个数,就意味着系统正在发生过载的问题,这时就得分析调查是哪里导致的问题,并要想办法优化了。
那么,在实际生产环境中,平均负载多高时,需要我们重点关注呢?
**在我看来,当平均负载高于 CPU 数量 70% 的时候,**你就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能。
**但 70% 这个数字并不是绝对的**,最推荐的方法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化趋势。当发现负载有明显升高趋势时,比如说负载翻倍了,你再去做分析和调查。
平均负载与 CPU 使用率
现实工作中,我们经常容易把平均负载和 CPU 使用率混淆,所以在这里,我也做一个区分。
可能你会疑惑,既然平均负载代表的是活跃进程数,那平均负载高了,不就意味着 CPU 使用率高吗?
我们还是要回到平均负载的含义上来,平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
而 CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:
* CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
* I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
* 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
平均负载案例分析
我们以三个示例分别来看这三种情况,并用 iostat、mpstat、pidstat 等工具,找出平均负载升高的根源。
测试准备工作
机器配置:2 CPU,8GB 内存。预先安装 stress 和 sysstat 包,如 apt install stress sysstat。
在这里,我先简单介绍一下 stress 和 sysstat。
* stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
* 而 sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpstat 和 pidstat。
* **mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。**
* **pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。**
**此外,每个场景都需要你开三个终端,登录到同一台 Linux 机器中。**
先安装stress sysstat
[root@VM-64-25-centos ~]# yum -y install stress sysstat
rpm update sysstat
[root@VM-64-25-centos ~]# wget https://rpmfind.net/linux/centos/8.1.1911/AppStream/x86_64/os/Packages/sysstat-11.7.3-2.el8.x86_64.rpm
--2020-10-12 16:12:25-- https://rpmfind.net/linux/centos/8.1.1911/AppStream/x86_64/os/Packages/sysstat-11.7.3-2.el8.x86_64.rpm
Resolving rpmfind.net (rpmfind.net)... 195.220.108.108
Connecting to rpmfind.net (rpmfind.net)|195.220.108.108|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 435888 (426K) [application/x-rpm]
Saving to: ‘sysstat-11.7.3-2.el8.x86_64.rpm’
100%[==========================================================================================================>] 435,888 15.0KB/s in 26s
2020-10-12 16:12:53 (16.4 KB/s) - ‘sysstat-11.7.3-2.el8.x86_64.rpm’ saved [435888/435888]
[root@VM-64-25-centos ~]# ls
sysstat-11.7.3-2.el8.x86_64.rpm
[root@VM-64-25-centos ~]# rpm -Uvh sysstat-11.7.3-2.el8.x86_64.rpm
warning: sysstat-11.7.3-2.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:sysstat-11.7.3-2.el8 ################################# [ 50%]
Cleaning up / removing...
2:sysstat-10.1.5-19.el7 ################################# [100%]
[root@VM-64-25-centos ~]#
测试1: CPU密集型进程
首先,我们在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:
[root@VM-64-25-centos ~]# stress --cpu 1 --timeout 600
stress: info: [5393] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
在第二个终端能看到
top - 15:18:24 up 110 days, 6:27, 3 users, load average: 0.98, 0.58, 0.27
Tasks: 139 total, 2 running, 137 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.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
%Cpu4 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu6 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu7 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 32779660 total, 29352228 free, 439752 used, 2987680 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 31936472 avail Mem
在第三个终端使用mpstat查看
[root@VM-64-25-centos ~]# mpstat -P ALL 5
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos) 10/12/2020 _x86_64_ (8 CPU)
03:16:54 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
03:16:59 PM all 12.56 0.00 0.05 0.00 0.00 0.00 0.00 0.00 0.00 87.39
03:16:59 PM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
03:16:59 PM 1 0.00 0.00 0.00 0.20 0.00 0.00 0.00 0.00 0.00 99.80
03:16:59 PM 2 0.00 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.80
03:16:59 PM 3 0.00 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.80
03:16:59 PM 4 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
03:16:59 PM 5 0.00 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.80
03:16:59 PM 6 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
03:16:59 PM 7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
使用pidstat来查看那个进程导致CPU使用率100%
[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos) 10/12/2020 _x86_64_ (8 CPU)
03:19:33 PM UID PID %usr %system %guest %CPU CPU Command
03:19:38 PM 0 5394 100.00 0.00 0.00 100.00 4 stress
03:19:38 PM 0 27987 0.20 0.00 0.00 0.20 2 barad_agent
03:19:38 PM 0 27988 0.60 0.40 0.00 1.00 2 barad_agent
03:19:38 PM 0 28457 0.20 0.20 0.00 0.40 2 YDService
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 5394 100.00 0.00 0.00 100.00 - stress
Average: 0 27987 0.20 0.00 0.00 0.20 - barad_agent
Average: 0 27988 0.60 0.40 0.00 1.00 - barad_agent
Average: 0 28457 0.20 0.20 0.00 0.40 - YDService
[root@VM-64-25-centos ~]#
测试2: I/O密集型进程
首先还是运行 stress 命令,但这次模拟 I/O 压力,即7个线程不停地执行,sync:
[root@VM-64-25-centos ~]# stress -i 7 --timeout 600
stress: info: [9331] dispatching hogs: 0 cpu, 7 io, 0 vm, 0 hdd
在第二个终端查看uptime的变化,我的测试机器是8C的,可以多观察一会
Every 2.0s: uptime Mon Oct 12 15:37:01 2020
15:37:01 up 110 days, 6:46, 3 users, load average: 6.67, 3.71, 1.69
在第三个终端查看CPU的变化
# 间隔5秒输出一组数据
[root@VM-64-25-centos ~]# mpstat -P ALL 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos) 10/12/2020 _x86_64_ (8 CPU)
03:37:28 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
03:37:33 PM all 0.10 0.00 26.70 0.90 0.00 0.07 0.00 0.00 0.00 72.22
03:37:33 PM 0 0.00 0.00 80.24 2.59 0.00 0.20 0.00 0.00 0.00 16.97
03:37:33 PM 1 0.20 0.00 41.43 1.20 0.00 0.00 0.00 0.00 0.00 57.17
03:37:33 PM 2 0.20 0.00 0.20 0.00 0.00 0.60 0.00 0.00 0.00 99.00
03:37:33 PM 3 0.20 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.40
03:37:33 PM 4 0.00 0.00 19.20 1.00 0.00 0.00 0.00 0.00 0.00 79.80
03:37:33 PM 5 0.00 0.00 30.86 1.20 0.00 0.00 0.00 0.00 0.00 67.94
03:37:33 PM 6 0.20 0.00 26.40 1.00 0.00 0.00 0.00 0.00 0.00 72.40
03:37:33 PM 7 0.00 0.00 14.60 0.60 0.00 0.00 0.00 0.00 0.00 84.80
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.10 0.00 26.70 0.90 0.00 0.07 0.00 0.00 0.00 72.22
Average: 0 0.00 0.00 80.24 2.59 0.00 0.20 0.00 0.00 0.00 16.97
Average: 1 0.20 0.00 41.43 1.20 0.00 0.00 0.00 0.00 0.00 57.17
Average: 2 0.20 0.00 0.20 0.00 0.00 0.60 0.00 0.00 0.00 99.00
Average: 3 0.20 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.40
Average: 4 0.00 0.00 19.20 1.00 0.00 0.00 0.00 0.00 0.00 79.80
Average: 5 0.00 0.00 30.86 1.20 0.00 0.00 0.00 0.00 0.00 67.94
Average: 6 0.20 0.00 26.40 1.00 0.00 0.00 0.00 0.00 0.00 72.40
Average: 7 0.00 0.00 14.60 0.60 0.00 0.00 0.00 0.00 0.00 84.80
[root@VM-64-25-centos ~]#
从这里可以看到,1分钟的负载增加到6.67,其中一个CPU的系统CPU使用率达到80.24,而iowait达到2.59,说明平均负载的升高是由iowait导致的
那么是那个进程导致iowait这么高,我们用pidstat来查询,如图展示发现是stress进程导致的
[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos) 10/12/2020 _x86_64_ (8 CPU)
03:39:55 PM UID PID %usr %system %guest %CPU CPU Command
03:40:00 PM 0 18 0.00 0.20 0.00 0.20 2 migration/2
03:40:00 PM 0 846 0.00 0.20 0.00 0.20 5 kworker/5:1H
03:40:00 PM 0 969 0.00 0.20 0.00 0.20 7 kworker/7:1H
03:40:00 PM 0 8401 0.00 0.20 0.00 0.20 3 kworker/u16:2
03:40:00 PM 0 9332 0.00 23.40 0.00 23.40 0 stress
03:40:00 PM 0 9333 0.00 52.40 0.00 52.40 5 stress
03:40:00 PM 0 9334 0.00 31.40 0.00 31.40 4 stress
03:40:00 PM 0 9335 0.00 26.60 0.00 26.60 6 stress
03:40:00 PM 0 9336 0.00 19.00 0.00 19.00 0 stress
03:40:00 PM 0 9337 0.00 36.20 0.00 36.20 7 stress
03:40:00 PM 0 9338 0.00 14.60 0.00 14.60 1 stress
03:40:00 PM 0 10203 0.00 0.40 0.00 0.40 2 kworker/u16:0
03:40:00 PM 0 27987 0.20 0.00 0.00 0.20 2 barad_agent
03:40:00 PM 0 27988 0.20 0.20 0.00 0.40 1 barad_agent
03:40:00 PM 0 28539 0.00 0.20 0.00 0.20 5 YDEdr
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 18 0.00 0.20 0.00 0.20 - migration/2
Average: 0 846 0.00 0.20 0.00 0.20 - kworker/5:1H
Average: 0 969 0.00 0.20 0.00 0.20 - kworker/7:1H
Average: 0 8401 0.00 0.20 0.00 0.20 - kworker/u16:2
Average: 0 9332 0.00 23.40 0.00 23.40 - stress
Average: 0 9333 0.00 52.40 0.00 52.40 - stress
Average: 0 9334 0.00 31.40 0.00 31.40 - stress
Average: 0 9335 0.00 26.60 0.00 26.60 - stress
Average: 0 9336 0.00 19.00 0.00 19.00 - stress
Average: 0 9337 0.00 36.20 0.00 36.20 - stress
Average: 0 9338 0.00 14.60 0.00 14.60 - stress
Average: 0 10203 0.00 0.40 0.00 0.40 - kworker/u16:0
Average: 0 27987 0.20 0.00 0.00 0.20 - barad_agent
Average: 0 27988 0.20 0.20 0.00 0.40 - barad_agent
Average: 0 28539 0.00 0.20 0.00 0.20 - YDEdr
[root@VM-64-25-centos ~]#
测试3: 大量进程的场景
当系统中运行的进程超出CPU运行能力时,就会出现等待CPU的进程.
比如,我们还是使用stress来测试,我们的CPU是8C,我们模拟20C.
[root@VM-64-25-centos ~]# stress -c 20 --timeout 600
stress: info: [13688] dispatching hogs: 20 cpu, 0 io, 0 vm, 0 hdd
使用uptime来看负载的变化,明显出现过载情况
Every 2.0s: uptime Mon Oct 12 16:17:19 2020
16:17:19 up 110 days, 7:26, 3 users, load average: 5.14, 1.30, 1.77
使用pidstat来查看进程
[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos) 10/12/2020 _x86_64_ (8 CPU)
04:19:51 PM UID PID %usr %system %guest %wait %CPU CPU Command
04:19:56 PM 0 13099 0.20 0.00 0.00 0.60 0.20 1 watch
04:19:56 PM 0 19633 42.20 0.00 0.00 57.80 42.20 1 stress
04:19:56 PM 0 19634 40.60 0.00 0.00 59.80 40.60 3 stress
04:19:56 PM 0 19635 40.40 0.00 0.00 59.40 40.40 0 stress
04:19:56 PM 0 19636 39.00 0.00 0.00 61.40 39.00 2 stress
04:19:56 PM 0 19637 36.20 0.00 0.00 63.80 36.20 6 stress
04:19:56 PM 0 19638 41.80 0.00 0.00 58.40 41.80 5 stress
04:19:56 PM 0 19639 42.00 0.00 0.00 57.40 42.00 2 stress
04:19:56 PM 0 19640 40.20 0.00 0.00 60.20 40.20 4 stress
04:19:56 PM 0 19641 40.60 0.00 0.00 59.40 40.60 4 stress
04:19:56 PM 0 19642 38.80 0.00 0.00 61.40 38.80 4 stress
04:19:56 PM 0 19643 41.40 0.00 0.00 58.80 41.40 5 stress
04:19:56 PM 0 19644 43.20 0.00 0.00 57.20 43.20 3 stress
04:19:56 PM 0 19645 36.60 0.00 0.00 64.00 36.60 0 stress
04:19:56 PM 0 19646 38.40 0.00 0.00 61.60 38.40 7 stress
04:19:56 PM 0 19647 38.60 0.00 0.00 61.20 38.60 5 stress
04:19:56 PM 0 19648 40.20 0.00 0.00 59.80 40.20 0 stress
04:19:56 PM 0 19649 43.00 0.00 0.00 57.20 43.00 6 stress
04:19:56 PM 0 19650 38.60 0.00 0.00 61.60 38.60 1 stress
04:19:56 PM 0 19651 37.40 0.00 0.00 62.60 37.40 2 stress
04:19:56 PM 0 19652 40.60 0.00 0.00 59.80 40.60 7 stress
04:19:56 PM 0 20344 0.00 0.20 0.00 0.00 0.20 1 pidstat
04:19:56 PM 0 27988 0.00 0.20 0.00 0.00 0.20 2 barad_agent
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 0 13099 0.20 0.00 0.00 0.60 0.20 - watch
Average: 0 19633 42.20 0.00 0.00 57.80 42.20 - stress
Average: 0 19634 40.60 0.00 0.00 59.80 40.60 - stress
Average: 0 19635 40.40 0.00 0.00 59.40 40.40 - stress
Average: 0 19636 39.00 0.00 0.00 61.40 39.00 - stress
Average: 0 19637 36.20 0.00 0.00 63.80 36.20 - stress
Average: 0 19638 41.80 0.00 0.00 58.40 41.80 - stress
Average: 0 19639 42.00 0.00 0.00 57.40 42.00 - stress
Average: 0 19640 40.20 0.00 0.00 60.20 40.20 - stress
Average: 0 19641 40.60 0.00 0.00 59.40 40.60 - stress
Average: 0 19642 38.80 0.00 0.00 61.40 38.80 - stress
Average: 0 19643 41.40 0.00 0.00 58.80 41.40 - stress
Average: 0 19644 43.20 0.00 0.00 57.20 43.20 - stress
Average: 0 19645 36.60 0.00 0.00 64.00 36.60 - stress
Average: 0 19646 38.40 0.00 0.00 61.60 38.40 - stress
Average: 0 19647 38.60 0.00 0.00 61.20 38.60 - stress
Average: 0 19648 40.20 0.00 0.00 59.80 40.20 - stress
Average: 0 19649 43.00 0.00 0.00 57.20 43.00 - stress
Average: 0 19650 38.60 0.00 0.00 61.60 38.60 - stress
Average: 0 19651 37.40 0.00 0.00 62.60 37.40 - stress
Average: 0 19652 40.60 0.00 0.00 59.80 40.60 - stress
Average: 0 20344 0.00 0.20 0.00 0.00 0.20 - pidstat
Average: 0 27988 0.00 0.20 0.00 0.00 0.20 - barad_agent
[root@VM-64-25-centos ~]#
可以看出,20个进程在争抢 8 个 CPU,每个进程等待 CPU 的时间(也就是代码块中的 %wait 列)高达 60%。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。
理解平均负载
平均负载提供了一个快速查看系统整体性能的手段,反映了整体的负载情况。但只看平均负载本身,我们并不能直接发现,到底是哪里出现了瓶颈。所以,在理解平均负载时,也要注意:
* 平均负载高有可能是 CPU 密集型进程导致的;
* 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
* 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。
pidstat输出中没有%wait的问题,是因为CentOS默认的sysstat稍微有点老,源码或者RPM升级到11.5.5版本以后就可以看到了。而Ubuntu的包一般都比较新,没有这个问题。