什么是平均负载
-
uptime
命令的输出中,前几列分别是当前时间,系统运行时间和当前登陆的用户数;$ uptime 02:34:03 up 2 days, 20:14, 1 user, load average: 0.63, 0.83, 0.88
-
而后三列则是一分钟、五分钟、15分钟的平均负载,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。
-
可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。
-
不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。
平均负载的合理值
-
平均负载最理想的情况是等于 CPU 个数。所以在评判平均负载时,首先要知道系统有几个 CPU,可以通过 top 命令或者从文件 /proc/cpuinfo 中读取:
# 关于grep和wc的用法请查询它们的手册或者网络搜索 $ grep 'model name' /proc/cpuinfo | wc -l 2
-
当平均负载比CPU个数大时,系统就出现了过载;而三个负载可以更加全方位的了解系统的负载情况:
- 如果 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
- 如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少,而过去 15 分钟内却有很大的负载。
- 反过来,如果 1 分钟的值远大于 15 分钟的值,就说明最近 1 分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦 1 分钟的平均负载接近或超过了 CPU 的个数,就意味着系统正在发生过载的问题。
-
在实际生产环境中,一般当平均负载高于CPU数量70%时,就应该对负载过高问题进行排查。
平均负载与CPU使用率
- 平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
- CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:
- CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
- I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
- 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
平均负载分析
-
安装
stress-ng
和sysstat
软件包,centos由于默认源里的sysstat包比较老,建议直接下载sysstat-11.7.3的rpm包:$ yum install -y stress-ng $ wget http://www.rpmfind.net/linux/centos/8.1.1911/AppStream/x86_64/os/Packages/sysstat-11.7.3-2.el8.x86_64.rpm $ yum install sysstat-11.7.3-2.el8.x86_64.rpm
- stress-ng 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
- sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能,这里主要使用其中的
mpstat
、iostat
和pidstat
; - mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标;
- pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。
案例一:CPU密集型进程
-
在第一个终端中运行
stress-ng
命令,模拟CPU使用率100%的场景:$ stress-ng --cpu 1 --timeout 600 stress-ng: info: [3150] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
-
在第二个终端中使用
uptime
查看平均负载变化情况:# -d 参数表示高亮显示变化的区域 $ watch -d uptime Every 2.0s: uptime Thu Sep 10 03:20:08 2020 03:22:52 up 36 min, 3 users, load average: 1.00, 0.61, 0.29
-
在第三个终端中运行
mpstat
查看CPU使用率变化的情况:# -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据 $ mpstat -P ALL 5 Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 05:09:25 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 05:09:30 AM all 24.21 0.00 0.25 0.00 0.00 0.05 0.00 0.00 0.00 75.48 05:09:30 AM 0 0.40 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.20 05:09:30 AM 1 0.20 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.60 05:09:30 AM 2 0.00 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.60 05:09:30 AM 3 99.79 0.00 0.00 0.00 0.00 0.21 0.00 0.00 0.00 0.00
-
从终端2中可以看到,1分钟的负载会满满增加到1.00,而终端3中可以看到正好有一个CPU的使用率为100%,但它的iowait始终是0,这说明平均负载的升高是由于CPU的使用率为100%;
-
然后使用
pidstat
命令来查看到底是哪个进程导致了CPU使用率为100%:# 间隔5秒后输出一组数据 $ pidstat -u 5 1 Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 05:11:36 AM UID PID %usr %system %guest %wait %CPU CPU Command 05:11:41 AM 0 2055 0.20 0.20 0.00 0.00 0.40 0 java 05:11:41 AM 27 2269 0.00 0.20 0.00 0.00 0.20 3 mysqld 05:11:41 AM 0 8647 99.60 0.00 0.00 0.00 99.60 3 stress-ng-cpu 05:11:41 AM 0 8657 0.20 0.40 0.00 0.00 0.60 1 watch 05:11:41 AM 0 8821 0.20 0.20 0.00 0.00 0.40 1 pidstat
这里可以看到,stress-ng的进程的CPU使用率为100%。
案例二:I/O密集型进程
-
使用
stress-ng
命令模拟I/O压力,即不停的执行sync:$ stress-ng -i1 --hdd 1 --timeout 600 stress-ng: info: [5567] dispatching hogs: 0 cpu, 1 io, 0 vm, 0 hdd
-
第二个终端还是运行
uptime
命令查看平均负载变化情况:$ watch -d uptime Every 2.0s: uptime Thu Sep 10 03:56:10 2020 03:56:10 up 1:10, 3 users, load average: 1.08, 0.44, 0.25
-
第三个终端运行
mpstat
命令查看CPU使用率变化情况:# 显示所有CPU的指标,并在间隔5秒输出一组数据 $ mpstat -P ALL 5 1 Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 04:26:48 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 04:26:53 AM all 0.66 0.00 21.50 39.33 0.00 2.03 0.00 0.00 0.00 36.48 04:26:53 AM 0 0.62 0.00 28.42 65.98 0.00 0.21 0.00 0.00 0.00 4.77 04:26:53 AM 1 0.48 0.00 5.54 3.13 0.00 4.82 0.00 0.00 0.00 86.02 04:26:53 AM 2 0.65 0.00 24.57 57.83 0.00 2.83 0.00 0.00 0.00 14.13 04:26:53 AM 3 0.86 0.00 25.54 25.75 0.00 0.64 0.00 0.00 0.00 47.21 Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle Average: all 0.66 0.00 21.50 39.33 0.00 2.03 0.00 0.00 0.00 36.48 Average: 0 0.62 0.00 28.42 65.98 0.00 0.21 0.00 0.00 0.00 4.77 Average: 1 0.48 0.00 5.54 3.13 0.00 4.82 0.00 0.00 0.00 86.02 Average: 2 0.65 0.00 24.57 57.83 0.00 2.83 0.00 0.00 0.00 14.13 Average: 3 0.86 0.00 25.54 25.75 0.00 0.64 0.00 0.00 0.00 47.21
-
这里可以看到,1分钟的平均负载会增加到1.08,其中一个CPU的%sys使用率达到28.42%,同时iowait达到了65.95%,这说明负载的升高是由于
iowait
升高引起的; -
查找哪个进程导致iowait升高,还是使用
pidstat
命令,pidstat -d
命令可以查看具体进程的IO读写情况:# 间隔5秒后输出一组数据,-u表示CPU指标 $ pidstat -u 5 1 Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 04:40:24 AM UID PID %usr %system %guest %wait %CPU CPU Command 04:40:29 AM 27 2269 0.20 0.00 0.00 0.00 0.20 3 mysqld 04:40:29 AM 0 6592 0.00 32.80 0.00 0.20 32.80 1 kworker/u256:1 04:40:29 AM 0 7170 0.60 0.40 0.00 0.00 0.99 1 watch 04:40:29 AM 0 7706 0.00 10.14 0.00 0.20 10.14 0 stress 04:40:29 AM 0 7707 0.40 72.76 0.00 0.20 73.16 0 stress 04:40:29 AM 0 7913 0.20 0.40 0.00 0.00 0.60 3 pidstat
[root@localhost ~]# pidstat -d Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 04:58:53 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command 04:58:53 AM 0 1 24.89 22044.05 7471.21 9 systemd 04:58:53 AM 0 1211 0.13 0.00 0.00 2 sshd 04:58:53 AM 0 1222 0.11 0.16 0.11 2 rsyslogd 04:58:53 AM 0 1230 5.06 0.00 0.00 44 containerd 04:58:53 AM 0 1246 2.56 0.00 0.00 41 libvirtd 04:58:53 AM 0 1250 10.64 0.05 0.00 58 dockerd 04:58:53 AM 0 1262 0.03 0.01 0.00 2 crond 04:58:53 AM 0 1271 0.01 0.00 0.00 0 agetty 04:58:53 AM 0 1572 0.04 0.00 0.00 0 master 04:58:53 AM 89 1577 0.04 0.00 0.00 1 qmgr 04:58:53 AM 0 2055 23.92 9.71 0.01 0 java 04:58:53 AM 27 2269 0.18 1.62 0.00 5 mysqld 04:58:53 AM 0 2341 0.19 0.00 0.00 1 sshd 04:58:53 AM 0 8497 0.00 0.00 0.00 6 kworker/2:1 04:58:53 AM 0 8536 0.00 0.00 339.51 1872 stress 04:58:53 AM 0 8537 0.00 2440.09 443.23 716 stress
可以看到还是stress进程引起的。
案例三:大量进程的场景
-
当系统中运行进程超出 CPU 运行能力时,就会出现等待 CPU 的进程,使用stress模拟16个进程的负载:
$ stress -c 8 --timeout 600 stress: info: [8303] dispatching hogs: 16 cpu, 0 io, 0 vm, 0 hdd
-
由于系统中只有4个CPU,明显比16个进程要少,所以CPU处于严重过载的状态:
[root@localhost ~]# uptime 04:47:29 up 2:01, 4 users, load average: 12.30, 4.62, 2.20
-
然后再使用
pidstat
查看进程的情况:$ pidstat -u 5 1 Linux 3.10.0-1127.el7.x86_64 (localhost.localdomain) 09/10/2020 _x86_64_ (4 CPU) 04:48:11 AM UID PID %usr %system %guest %wait %CPU CPU Command 04:48:16 AM 0 9 0.00 0.20 0.00 0.39 0.20 2 rcu_sched 04:48:16 AM 0 960 0.00 0.20 0.00 0.79 0.20 2 vmtoolsd 04:48:16 AM 0 1250 0.39 0.00 0.00 0.00 0.39 1 dockerd 04:48:16 AM 0 2055 0.20 0.00 0.00 0.00 0.20 0 java 04:48:16 AM 0 8304 25.15 0.00 0.00 74.26 25.15 1 stress 04:48:16 AM 0 8305 24.95 0.00 0.00 74.85 24.95 0 stress 04:48:16 AM 0 8306 25.34 0.00 0.00 74.26 25.34 1 stress 04:48:16 AM 0 8307 25.93 0.00 0.00 73.67 25.93 0 stress 04:48:16 AM 0 8308 24.36 0.00 0.00 75.05 24.36 3 stress 04:48:16 AM 0 8309 25.54 0.20 0.00 73.87 25.74 0 stress 04:48:16 AM 0 8310 26.13 0.00 0.00 72.69 26.13 2 stress 04:48:16 AM 0 8311 23.97 0.00 0.00 75.44 23.97 3 stress 04:48:16 AM 0 8312 24.56 0.00 0.00 75.44 24.56 1 stress 04:48:16 AM 0 8313 24.56 0.00 0.00 74.85 24.56 2 stress 04:48:16 AM 0 8314 23.97 0.00 0.00 75.25 23.97 1 stress 04:48:16 AM 0 8315 24.17 0.00 0.00 75.25 24.17 0 stress 04:48:16 AM 0 8316 23.97 0.00 0.00 76.42 23.97 3 stress 04:48:16 AM 0 8317 25.74 0.00 0.00 73.87 25.74 2 stress 04:48:16 AM 0 8318 23.97 0.00 0.00 76.23 23.97 2 stress 04:48:16 AM 0 8319 24.36 0.00 0.00 74.66 24.36 3 stress 04:48:16 AM 0 8431 0.20 0.20 0.00 0.79 0.39 3 pidstat
可以看到,16个stress进程在争抢4个CPU,每个进程等待CPU的时间(即%wait列)高达75%,这些超出CPU计算能力的进程,最终导致了CPU的过载。
总结
通过这三个案例,再来归纳一下平均负载的理解。
平均负载提供了一个快速查看系统整体性能的手段,反映了整体的负载情况。但只看平均负载本身,我们并不能直接发现,到底是哪里出现了瓶颈。所以,在理解平均负载时,也要注意:
- 平均负载高有可能是 CPU 密集型进程导致的;
- 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
- 当发现负载高的时候,可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。