平均负载基本含义
系统变慢时使用top或uptime查看系统平均负载情况:
[root@localhost ~]# uptime
16:34:18 up 0 min, 2 users, load average: 0.08, 0.03, 0.01
uptime命令每列含义:
16:34:18 #系统当前时间
up 40 min #系统运行时间
2 users #正在登陆用户数
load average: 0.08, 0.03, 0.01 #过去1分钟负载,过去5分钟负载、过去15分钟负载
系统负载平均数是单位时间内,系统处于可运行或不可中断状态的进程的平均数,即平均活跃进程数,它与CPU使用率没有直接关系。
可运行状态的进程是指正在使用CPU或正在等待CPU的进程,即使用ps命令查看到的处于R(Running/Runnable)状态的进程。
不可中断状态的进程是正处于内核态关键流程中的进程,并且这些流程不可打断,如常见的等待硬件设备的I/O响应,即使用ps命令查看到的D(Uninterruptible Sleep,也称为Disk Sleep)状态的进程。 例如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在未得到磁盘响应前它不能被其他进程中断,此时进程就处于不可中断状态。如果进程被打断了,就容易出现磁盘数据与进程数据不一致问题。所以不可中断状态实际上是系统对进程和硬件设备的一种保护机制。
所以平均负载就是平均活跃进程数,直观理解是单位时间内的活跃进程数,但它实际上是活跃进程数的指数衰减平均值(系统的一种更快速的计算方式,可以理解成活跃进程数的平均值)。
既然平均的是活跃进程数,那么最理想的是,每个CPU上都刚好运行一个进程,这样每个CPU都得到充分利用。比如当平均负载为2时,意味着什么?
- 在2个CPU的系统上,意味着所有CPU都刚好被完全占用
- 在4个CPU的系统上,意味着CPU有50%的空闲
- 在1个CPU的系统上,意味着有1/2的进程竞争不到CPU
平均负载为多少时合理
平均负载最理想情况是等于CPU个数。所以在评判平均负载时,首先需要知道系统有多少个cpu
[root@localhost ~]# cat /proc/cpuinfo| grep "processor"| wc -l #查看逻辑CPU
2
获取CPU的个数后,就可以判断出,当平均负载比CPU个数还要大时,系统已经出现过载。uptime给出平均负载3个值都应该查看,3个不同时间间隔的平均值,给我们提供了分析系统负载趋势的数据来源,让我们更全面、更立体的理解目前的负载状况。 例如,北京初秋的天气,如果只看中午温度,可能认为在炎热的夏天,但是结合早、中、晚3个时间的温度,基本可以了解这一天天气状态。
同样对于CPU的三个负载时间段也如此。 例如,在单CPU系统上看到平均负载为1.73,0.60,7.98,此刻表示在过去1分钟内,系统又73%的超载,而在15分钟内有689%的超载,从整体趋势看,系统的负载在降低。解释如下:
- 1分钟、5分钟、15分钟的三个值基本相同或者相差不大,说明系统负载很平稳
- 1分钟的值远远小于15分钟的值,说明系统最近1分钟的负载在减少,但过去15分钟内负载很大
- 1分钟的值远远大于15分钟的值,说明系统最近1分钟的负载在增加,这种增加可能只是临时的,也可能持续增加,所以需要持续观察。但1分钟的平均负载接近或超过了CPU的个数,就意味着系统正在发生过载的问题,此时就要分析调查什么问题导致,并想办法优化
在实际生产环境中平均负载高于CPU数量的70%,就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响业务的正常功能。但70%并不是绝对的,最推荐的方法,还是把系统的平均负载监控起来,根据更多的历史数据,判断负载的变化趋势。当发现负载有明显升高趋势时,例如负载翻倍了,再去做分析和调查。
平均负载与CPU使用率
平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
等待I/O就是某个进程读取磁盘,此时这个进程就处于不可中断睡眠状态,实际没有占用CPU,但算作平均负载。所以平均负载高不一定CPU使用率高,可能是IO瓶颈导致平均负载高。
CPU使用率是单位时间内CPU繁忙情况的统计,与平均负载不一定完全对应。例如:
- CPU密集型进程,使用大量CPU会导致平均负载升高,此时两者一致;
- I/O密集型进程,等待I/O也会导致平均负载升高,但CPU使用率不一定很高;
- 大量等待CPU的进程调度也会导致平均负载升高,此时CPU使用率也会比较高。
平均负载案例分析
实验环境准备
OS:Centos7.9
机器配置:2核CPU,8GB内存
安装stress和sysstat包,并打开3个终端连接同一台服务器
[root@localhost ~]# yum -y install stress sysstat
stress:一款Linux系统压力测试工具,通常用于模拟系统上的负载,以测试系统在高负载条件下的性能或稳定性。这里用作异常进程模拟平均负载升高的场景。
sysstat:包含了常用的Linux性能工具,用来监控和分析系统的性能。本此实验会用到mpstat和pidstat命令。
mpstat:一个常用的多核CPU性能分析工具,用来实时查看每个CPU的性能指标,以及所有CPU的平均指标。
pidstat:一个常用的进程性能分析工具,用来实时查看进程的CPU、内存、I/O以及上下文切换等性能指标。
测试前查看平均负载情况:
[root@localhost ~]# uptime
10:18:55 up 44 min, 2 users, load average: 0.00, 0.04, 0.06
场景一:CPU密集型进程
首先,在第一个终端运行stress命令,模拟一个CPU使用率100%的场景:
#--cpu 1:在一个CPU核心上模拟负载
#--timeout 600:stress工具将在运行后的600秒(10分钟)之后自动停止
[root@localhost ~]# stress --cpu 1 --timeout 600
stress: info: [12348] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
接着,在第二个终端运行uptime查看平均负载的变化情况:
#-d:高亮显示变化的区域
[root@localhost ~] watch -d uptime
Every 2.0s: uptime Wed Sep 27 10:27:06 2023
10:27:06 up 52 min, 4 users, load average: 0.99, 0.59, 0.28
最后,在第三个终端运行mpstat查看CPU使用率变化情况:
#-P ALL:显示每个CPU核心的详细信息,而不仅仅是汇总信息
#5:每隔5秒生成一次性能统计信息的报告
[root@localhost ~]# mpstat -P ALL 5
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 09/27/2023 _x86_64_ (2 CPU)
10:27:39 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:27:44 AM all 50.05 0.00 0.10 0.00 0.00 0.00 0.00 0.00 0.00 49.85
10:27:44 AM 0 8.78 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 91.22
10:27:44 AM 1 91.40 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 8.40
结论:从第二终端看到,1分钟的平均负载会慢慢增加到1.00。从终端三中看到,只有一个CPU的使用率是100%,而且%iowait 是0。这说明,平均负载的升高是由于 CPU 使用率为100%引起的。
使用pidstat查看哪个进程导致CPU使用率为100%:
#-u:显示关于CPU使用情况的统计信息
#5:每隔 5 秒生成一次报告
#1:生成一次报告后退出
[root@localhost ~]# pidstat -u 5 1
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 09/27/2023 _x86_64_ (2 CPU)
10:28:54 AM UID PID %usr %system %guest %CPU CPU Command
10:28:59 AM 0 12349 100.00 0.00 0.00 100.00 0 stress
10:28:59 AM 0 12352 0.20 0.00 0.00 0.20 1 watch
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 12349 100.00 0.00 0.00 100.00 - stress
Average: 0 12352 0.20 0.00 0.00 0.20 - watch
从这里可以看出,stress进程的CPU使用率为100%。
场景二:I/O密集型进程
首先,第一个终端运行stress命令模拟I/O压力,即不停地执行sync:
#1:要模拟一个I/O负载,1表示每个子进程将执行一个I/O操作
[root@localhost ~]# stress -i 1 --timeout 600
stress: info: [12755] dispatching hogs: 0 cpu, 1 io, 0 vm, 0 hdd
接着,第二个终端运行uptime查看平均负载的变化情况:
[root@localhost ~] watch -d uptime
Every 2.0s: uptime Wed Sep 27 14:46:04 2023
14:46:04 up 5:11, 4 users, load average: 1.25, 0.69, 0.32
最后,第三个终端运行mpstat查看CPU使用率的变化情况:
[root@localhost ~]# mpstat -P ALL 5 1
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 09/27/2023 _x86_64_ (2 CPU)
02:44:13 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
02:44:18 PM all 2.30 0.00 47.90 0.00 0.00 0.00 0.00 0.00 0.00 49.80
02:44:18 PM 0 0.20 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.60
02:44:18 PM 1 4.21 0.00 95.79 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 2.30 0.00 47.90 0.00 0.00 0.00 0.00 0.00 0.00 49.80
Average: 0 0.20 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.60
Average: 1 4.21 0.00 95.79 0.00 0.00 0.00 0.00 0.00 0.00 0.00
结论:从第二终端可以看出,1分钟的平均负载会慢慢增加到1.25。从第三个终端可以看出,其中一个CPU的系统CPU使用率升高到95.79,但%iowait没有变化,是因为stress使用sync()系统调用,它的作用是刷新缓冲区内存到磁盘。产生N个进程,每个进程循环调用sync将内存缓冲区内容写到磁盘上,产生IO压力。如果缓冲区内数据较少,写到磁盘中的数据也较少,不会产生IO压力。在SSD磁盘环境中尤为明显,很可能iowait总是0,却因为大量调用系统调用sync,导致系统CPU使用率sys升高。
对于新安装的虚拟机,缓冲区可能比较小,无法产生大的IO压力,此时大部分被系统调用消耗掉,所以只有CPU使用率升高。解决方式是第一个终端使用stress的下一代stress-ng:
[root@localhost ~]# yum -y install stress-ng
#--hdd:读写临时文件
[root@localhost ~]# stress-ng -i 1 --hdd 1 --timeout 600
stress-ng: info: [12268] dispatching hogs: 1 hdd, 1 io
第三个终端重新运行mpstat查看CPU使用率的变化情况:
[root@localhost ~]# mpstat -P ALL 5 1
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 10/07/2023 _x86_64_ (2 CPU)
04:24:55 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
04:25:00 PM all 0.50 0.00 0.70 98.80 0.00 0.00 0.00 0.00 0.00 0.00
04:25:00 PM 0 0.60 0.00 1.00 98.40 0.00 0.00 0.00 0.00 0.00 0.00
04:25:00 PM 1 0.40 0.00 0.20 99.40 0.00 0.00 0.00 0.00 0.00 0.00
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.50 0.00 0.70 98.80 0.00 0.00 0.00 0.00 0.00 0.00
Average: 0 0.60 0.00 1.00 98.40 0.00 0.00 0.00 0.00 0.00 0.00
Average: 1 0.40 0.00 0.20 99.40 0.00 0.00 0.00 0.00 0.00 0.00
结论:其中一个CPU的系统CPU使用率为0.2,而%iowait高达99.40,此时说明平均负载的升高是由于iowait的升高。
使用pidstat查看哪个进程导致CPU使用率sys高:
[root@localhost ~]# pidstat -u 5 1
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 10/07/2023 _x86_64_ (2 CPU)
04:25:18 PM UID PID %usr %system %guest %CPU CPU Command
04:25:23 PM 0 9 0.00 0.20 0.00 0.20 0 rcu_sched
04:25:23 PM 0 11749 0.00 0.20 0.00 0.20 0 kworker/0:0
04:25:23 PM 0 11933 0.00 0.20 0.00 0.20 0 kworker/u4:1
04:25:23 PM 0 11934 0.20 0.40 0.00 0.60 0 watch
04:25:23 PM 0 12269 0.00 7.34 0.00 7.34 0 stress-ng-hdd
04:25:23 PM 0 12270 0.00 0.40 0.00 0.40 1 stress-ng-io
04:25:23 PM 0 12306 0.20 0.40 0.00 0.60 0 pidstat
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 9 0.00 0.20 0.00 0.20 - rcu_sched
Average: 0 11749 0.00 0.20 0.00 0.20 - kworker/0:0
Average: 0 11933 0.00 0.20 0.00 0.20 - kworker/u4:1
Average: 0 11934 0.20 0.40 0.00 0.60 - watch
Average: 0 12269 0.00 7.34 0.00 7.34 - stress-ng-hdd
Average: 0 12270 0.00 0.40 0.00 0.40 - stress-ng-io
Average: 0 12306 0.20 0.40 0.00 0.60 - pidstat
从这里可以看出,是stress进程导致。
场景三:大量进程的场景
当系统中运行进程超出CPU运行能力时,就会出现等待CPU进程。
首先,第一个终端使用stress,模拟8个进程并发:
[root@localhost ~]# stress -c 8 --timeout 600
stress: info: [23779] dispatching hogs: 8 cpu, 0 io, 0 vm, 0 hdd
接着,第二个终端运行uptime查看平均负载的变化情况:
[root@localhost ~] watch -d uptime
Every 2.0s: uptime Thu Sep 28 09:06:02 2023
09:06:02 up 23:31, 4 users, load average: 8.09, 4.78, 2.04
最后,第三个终端运行pidstat查看进程情况:
[root@localhost ~]# pidstat -u 5 1
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 09/28/2023 _x86_64_ (2 CPU)
09:02:34 AM UID PID %usr %system %guest %CPU CPU Command
09:02:39 AM 0 23780 24.70 0.00 0.00 24.70 0 stress
09:02:39 AM 0 23781 24.70 0.00 0.00 24.70 0 stress
09:02:39 AM 0 23782 24.70 0.00 0.00 24.70 0 stress
09:02:39 AM 0 23783 24.70 0.00 0.00 24.70 1 stress
09:02:39 AM 0 23784 24.51 0.00 0.00 24.51 1 stress
09:02:39 AM 0 23785 24.90 0.00 0.00 24.90 1 stress
09:02:39 AM 0 23786 24.51 0.00 0.00 24.51 0 stress
09:02:39 AM 0 23787 24.70 0.00 0.00 24.70 1 stress
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 23780 24.70 0.00 0.00 24.70 - stress
Average: 0 23781 24.70 0.00 0.00 24.70 - stress
Average: 0 23782 24.70 0.00 0.00 24.70 - stress
Average: 0 23783 24.70 0.00 0.00 24.70 - stress
Average: 0 23784 24.51 0.00 0.00 24.51 - stress
Average: 0 23785 24.90 0.00 0.00 24.90 - stress
Average: 0 23786 24.51 0.00 0.00 24.51 - stress
Average: 0 23787 24.70 0.00 0.00 24.70 - stress
结论:第二个终端可以看出,系统只有2个CPU比8个进程要少得多,所以系统CPU处于严重过载状态,平均负载高达8.09。第三个终端可以看出,由于8个进程具有相似的CPU使用率(%usr列),这表明它们在争抢2个CPU资源。
小结
归纳平均负载的理解,平均负载提供了一个快速查看系统整体性能的手段,反映了系统整体的负载情况。但只看平均负载并不能直接发现瓶颈具体出现在什么地方,所以在理解平均负载时,也要注意:
- 平均负载高有可能是CPU密集型进程导致的;
- 平均负载高并不一定代表CPU使用率高,还可能使I/O繁忙;
- 当发现负载高,可以使用mpstat、pidstat等工具,辅助分析负载的来源。