最近在极客时间学习了倪朋飞老师的《Linux性能优化实战》专题,里面讲到了linux的平均负载这个概念。也就是load average。现在谈谈对平均负载的理解,并整理为笔记。
1.概念
1.1 如何查看系统的平均负载?
当我们通过ssh进入linux系统之后,通常来说,有两种方式可以查看这个load average.
执行uptime
[root@m162p201 ~]# uptime
15:26:21 up 621 days, 8:06, 1 user, load average: 0.00, 0.01, 0.05
执行top
[root@m162p201 ~]# top
top - 15:26:59 up 621 days, 8:07, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 106 total, 1 running, 105 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.5 us, 0.5 sy, 0.0 ni, 98.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.2 st
KiB Mem : 8175664 total, 2006684 free, 4863032 used, 1305948 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 2626032 avail Mem
通过上述两种方法,都可以得到load average。 我们看到这个load average的值由3个分隔的数字构成。 分别代表过去1分钟、5分钟、15分钟三个时间段系统的平均负载。
1.2 平均负载概念
让我们看看平均负载的解释,man uptime中的描述如下:
uptime gives a one line display of the following information. The current time, how long the system has been running, how many users are currently logged on, and the system load averages for the
past 1, 5, and 15 minutes.
This is the same information contained in the header line displayed by w(1).
System load averages is the average number of processes that are either in a runnable or uninterruptable state. A process in a runnable state is either using the CPU or waiting to use the CPU. A
process in uninterruptable state is waiting for some I/O access, eg waiting for disk. The averages are taken over the three time intervals. Load averages are not normalized for the number of
CPUs in a system, so a load average of 1 means a single CPU system is loaded all the time while on a 4 CPU system it means it was idle 75% of the time.
这个定义为:系统的平均负载(load averages)是处于Runnable(运行)状态和Uninterruptable(不可中断)状态的两种状态下的进程在单位时间内的平均数。对,没有看错,这里说的是平均的进程数量,与CPU本身的使用率没有直接关系。这个load averages实际上表示的是系统中的平均活跃进程数。
对于进程的这两种状态
在前面学过jvm的线程模型,线程的状态也与进程的状态类似,实际上这个状态指正在使用或者正在等待使用的CPU进程。通过PS中看到的R状态的进程。
不可中断的进程,指的是该进程处于内核态关键流程中的状态,这些流程是不能被中断的。比如在等待硬件设备或者是I/O响应,这也是我们在PS过程中看到的D状态进程。这些进程如果被中断,将会造成数据不一致问题或者故障。
因此,我们可以讲系统的平均负载理解为单位时间内的平均的活跃进程数。 那么我们如果需要知道一个服务器上负载究竟是多少合适呢?既然是单位时间内的平均活跃进程数,那么最理想的状态就是,一个CPU运行一个进程,这样每个CPU都将充分被利用。假如我们得到的平均负载为2的话,那么在只有1个CPU的系统中,将会形成系统过载,意味着其中一半的进程竞争不到资源。而2个CPU的系统中,则意味着CPU刚好被利用。在4个CPU的系统中,则CPU可能存在50%的空闲。
1.3 扩展
1.3.1 ps中的进程状态
通过ps命令我们可以查看linux中的进程状态,通常的如 ps -aux。
[root@m162p201 ~]# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 51720 3484 ? Ss 2019 203:55 /usr/lib/systemd/systemd --system --deserialize 22
root 2 0.0 0.0 0 0 ? S 2019 0:04 [kthreadd]
root 3 0.0 0.0 0 0 ? S 2019 9:45 [ksoftirqd/0]
root 7 0.0 0.0 0 0 ? S 2019 0:07 [migration/0]
root 8 0.0 0.0 0 0 ? S 2019 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S 2019 262:40 [rcu_sched]
root 10 0.0 0.0 0 0 ? S 2019 4:27 [watchdog/0]
root 11 0.0 0.0 0 0 ? S 2019 4:04 [watchdog/1]
root 12 0.0 0.0 0 0 ? S 2019 0:06 [migration/1]
root 13 0.0 0.0 0 0 ? S 2019 26:33 [ksoftirqd/1]
root 17 0.0 0.0 0 0 ? S< 2019 0:00 [khelper]
root 18 0.0 0.0 0 0 ? S 2019 0:00 [kdevtmpfs]
root 19 0.0 0.0 0 0 ? S< 2019 0:00 [netns]
root 20 0.0 0.0 0 0 ? S 2019 0:36 [khungtaskd]
root 21 0.0 0.0 0 0 ? S< 2019 0:00 [writeback]
root 22 0.0 0.0 0 0 ? S< 2019 0:00 [kintegrityd]
root 23 0.0 0.0 0 0 ? S< 2019 0:00 [bioset]
root 24 0.0 0.0 0 0 ? S< 2019 0:00 [kblockd]
上述表中的列分别为:
列名 | 说明 |
---|
USER | 进程所有者用户名。 | PID | 用来唯一标识的进程ID(进程号) | %CPU | 进程占用CPU的百分比。 | %MEM | 进程占用内存的百分比。 | VSZ | 进程使用的虚拟内存的大小,单位KB | RSS | 进程使用物理内存的总page数,这是内存管理的最小单位,每个page为4k | TTY | 进程所在的终端ID | STAT | 进程的状态,后面详细介绍。 | START | 进程启动时间 | TIME | 进程占用总CPU的时间 | COMMAND | 进程执行的命令和参数 |
对于STAT的常用状态如下表:
状态 | 说明 |
---|
R | 可运行状态,此时进程处于正在运行或者正在运行的队列中准备运行 | S | 可中断状态。处于可中断的某一状态的进程可以被中断信号中断。 | D | 不可中断状态。处于不可中断的等待状态的进程不可被中断信号中断,将一直等待事件发生或者直到某种系统资源完成。 | T | 暂停状态,处于暂停状态的进程被暂停运行 | Z | 僵死状态,每个进程在运行结束之后都会处于僵死状态,等待父进程的调用而释放资源,处于该状态的进程已经运行结束,但是其父进程并没有释放其资源,或者父进程已经死亡 |
进程的附加状态说明:
附加状态 | 说明 |
---|
< | 高优先级进程。 | N | 低优先级进程。 | L | 存在某些页面被锁在内存中 | s | 主进程 | l | 开启了多线程的进程 | + | 前台进程 |
1.3.2 如何查看CPU数量
可以通过grep获取/proc/cpuinfo来得到。
[root@m162p201 ~]# grep 'model name' /proc/cpuinfo |wc -l
2
2.平均负载的合理数值
在得到系统的CPU个数之后,我们就很容易来判断系统的平均负载了,当平均负载大于CPU个数,说明系统肯定是过载了,如果当平均负载低于CPU个数,貌似这种情况是可以接受的。 但是现在问题是,load averages存在3个值,我们应该参考哪个值呢?
实际上,这三个平均负载,我们在系统中都要进行参考。必须结合才能反应系统的负载情况。这三个值分别代表了1分钟、5分钟、15分钟内的平均负载。
结合这三个值,我们可以做出如下预测: 如果1分钟、5分钟、15分钟三个值基本相同,或者相差不大,那么说明系统负载平稳。 如果1分钟的值远小于15分钟的值,那么说明系统最近1分钟内负载降低,而过去15分钟内存在很高的负载。 如果1分钟的值,远大于15分钟,说明1分钟的负载在增加,但是这种增加,也可能是临时增加,需要持续观察。 一旦1分钟内的值接近或者超过了CPU个数,由于这个值记录的是系统已经发生的,所以要想办法进行优化,分析问题产生的原因。
参考课程中的例子: 如果在一个单核CPU的系统中平均负载为:1.75,0.80,8.75 那么说明在过去1分钟内,系统存在75%的超载,过去5分钟,系统没有超载,而过去的15分钟,系统存在775%的超载。 从这个趋势来看,系统的整体负载在降低。 按照课程的经验值,通常情况下,当平均负载高于CPU数量70%的时候,就应该对负载进行排查了,一旦系统负载过高,可能对整体服务的性能造成影响。 当然,这也不是绝对值,因为对于不同类型的服务,其系统负载不同,因此还是要根据系统监控,根据历史数据来进行判断。
3.平均负载与CPU使用率的关系
平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。因此,它不仅包括了正在使用CPU的进程,还包括等待CPU和等待I/O的进程以及处于等待中的一切不可中断的进程,而CPU使用率,是单位时间内CPU繁忙情况的统计,跟平均负载并不一定完全对应。
- CPU密集型进程,使用大量CPU进行密集运算会导致平均负载升高,此时这两者是一致的;
- I/O密集型进程,等待I/O也会导致平均负载升高,但CPU使用率不一定很高;
- 大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高。
4.测试案例
现在对平均负载的案例进行测试,环境准备:
系统环境htop
硬件情况如上图。2CPU,8G内存。 操作系统Centos7.7
[root@m162p201 ~]# lsb_release -a
LSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
Distributor ID: CentOS
Description: CentOS Linux release 7.7.1908 (Core)
Release: 7.7.1908
Codename: Core
需要安装软件:
yum install -y stress sysstat
stress是一个Linux压力测试工具,存在于epel包中。sysstat包含了常用的linux性能工具。用于监控和分析系统性能。这个包括两个命令,mpstat和pidstat,其中mpstat是一个多核的CPU性能分析工具,用来查看CPU的实时性能指标和平均性能指标。而pidstat则是一个性能分析的工具。可以实时查看PU、内存、I/O 以及上下文切换等性能指标。 在测试过程中,需要打开三个终端,需要注意的是终端类型不能为Xterm。
4.1 CPU密集型进程
第一个终端中运行:
[root@m162p201 ~]# stress --cpu 1 --timeout 600
stress: info: [11708] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
第二个终端,采用watch运行uptime
watch -d uptime
uptime截图
第三个终端,通过mpstat查看CPU的变化情况。
[root@m162p201 ~]# mpstat -P ALL 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
06:44:39 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
06:44:44 PM all 50.96 0.00 0.61 0.00 0.00 0.00 0.00 0.00 0.00 48.43
06:44:44 PM 0 4.49 0.00 1.22 0.00 0.00 0.00 0.00 0.00 0.00 94.29
06:44:44 PM 1 96.59 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3.41
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 50.96 0.00 0.61 0.00 0.00 0.00 0.00 0.00 0.00 48.43
Average: 0 4.49 0.00 1.22 0.00 0.00 0.00 0.00 0.00 0.00 94.29
Average: 1 96.59 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3.41
通过上述三个案例可以发现,1分钟的负载逐渐上升到1.2,而此时,1号CPU的负载高达96.5%,但是这个CPU的iowait以及其他指标都为0,只有3.41%的idle。 这说明,系统的平均负载正是由于CPU的高使用率造成。 那么,究竟是哪个进程导致的呢,我们通过pidstat来查看:
[root@m162p201 ~]# pidstat -u 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
06:49:57 PM UID PID %usr %system %guest %CPU CPU Command
06:50:02 PM 0 1 0.00 0.20 0.00 0.20 0 systemd
06:50:02 PM 0 9 0.00 0.20 0.00 0.20 0 rcu_sched
06:50:02 PM 1008 5244 0.20 0.80 0.00 1.00 0 java
06:50:02 PM 1008 8031 6.60 5.20 0.00 11.80 1 java
06:50:02 PM 1007 10589 0.00 0.80 0.00 0.80 1 java
06:50:02 PM 0 11709 99.80 0.20 0.00 100.00 1 stress
06:50:02 PM 0 11785 0.20 0.00 0.00 0.20 0 watch
06:50:02 PM 0 18040 0.40 0.60 0.00 1.00 0 etcd
06:50:02 PM 998 18737 0.00 0.20 0.00 0.20 0 polkitd
06:50:02 PM 1001 32703 0.00 0.20 0.00 0.20 1 java
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 1 0.00 0.20 0.00 0.20 - systemd
Average: 0 9 0.00 0.20 0.00 0.20 - rcu_sched
Average: 1008 5244 0.20 0.80 0.00 1.00 - java
Average: 1008 8031 6.60 5.20 0.00 11.80 - java
Average: 1007 10589 0.00 0.80 0.00 0.80 - java
Average: 0 11709 99.80 0.20 0.00 100.00 - stress
Average: 0 11785 0.20 0.00 0.00 0.20 - watch
Average: 0 18040 0.40 0.60 0.00 1.00 - etcd
Average: 998 18737 0.00 0.20 0.00 0.20 - polkitd
Average: 1001 32703 0.00 0.20 0.00 0.20 - java
可以发现,这正是由于stress的CPU达到100%所致。
4.2 I/O密集型
我们在终端1中执行:
[root@m162p201 ~]# stress -i 1 --timeout 600
stress: info: [12898] dispatching hogs: 0 cpu, 1 io, 0 vm, 0 hdd
由于测试io,实际上就是调用sync不断的同步磁盘数据。 在终端2中,通过watch查看:
uptime截图
在终端3中通过mpstat查看:
[root@m162p201 ~]# mpstat -P ALL 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
06:54:14 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
06:54:19 PM all 0.62 0.00 46.15 1.13 0.00 0.00 0.10 0.00 0.00 52.00
06:54:19 PM 0 1.42 0.00 1.22 0.00 0.00 0.00 0.00 0.00 0.00 97.36
06:54:19 PM 1 0.00 0.00 92.28 2.30 0.00 0.00 0.00 0.00 0.00 5.43
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.62 0.00 46.15 1.13 0.00 0.00 0.10 0.00 0.00 52.00
Average: 0 1.42 0.00 1.22 0.00 0.00 0.00 0.00 0.00 0.00 97.36
Average: 1 0.00 0.00 92.28 2.30 0.00 0.00 0.00 0.00 0.00 5.43
可以看到1分钟内,系统负载上升到, 1.22而1号CPU的sys状态为92.8,这说明load的上升是由于IO造成的。 执行pidstat:
[root@m162p201 ~]# pidstat -u 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
06:57:49 PM UID PID %usr %system %guest %CPU CPU Command
06:57:54 PM 1008 5244 0.20 0.80 0.00 1.00 0 java
06:57:54 PM 0 6533 0.00 0.20 0.00 0.20 0 kworker/u4:2
06:57:54 PM 1008 8031 0.00 0.40 0.00 0.40 1 java
06:57:54 PM 0 8985 0.00 0.20 0.00 0.20 1 kworker/1:2H
06:57:54 PM 1002 9636 0.00 0.20 0.00 0.20 1 java
06:57:54 PM 1007 10589 0.20 0.80 0.00 1.00 1 java
06:57:54 PM 0 12899 0.00 93.00 0.00 93.00 0 stress
06:57:54 PM 0 12907 0.20 0.20 0.00 0.40 1 watch
06:57:54 PM 0 12921 0.00 0.20 0.00 0.20 0 kworker/u4:0
06:57:54 PM 0 13490 0.00 0.20 0.00 0.20 1 pidstat
06:57:54 PM 0 13497 0.00 0.20 0.00 0.20 0 kworker/u4:1
06:57:54 PM 0 18691 0.20 0.00 0.00 0.20 0 irqbalance
06:57:54 PM 0 18778 0.00 0.20 0.00 0.20 1 kworker/1:2
06:57:54 PM 1001 32703 0.00 0.20 0.00 0.20 1 java
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 1008 5244 0.20 0.80 0.00 1.00 - java
Average: 0 6533 0.00 0.20 0.00 0.20 - kworker/u4:2
Average: 1008 8031 0.00 0.40 0.00 0.40 - java
Average: 0 8985 0.00 0.20 0.00 0.20 - kworker/1:2H
Average: 1002 9636 0.00 0.20 0.00 0.20 - java
Average: 1007 10589 0.20 0.80 0.00 1.00 - java
Average: 0 12899 0.00 93.00 0.00 93.00 - stress
Average: 0 12907 0.20 0.20 0.00 0.40 - watch
Average: 0 12921 0.00 0.20 0.00 0.20 - kworker/u4:0
Average: 0 13490 0.00 0.20 0.00 0.20 - pidstat
Average: 0 13497 0.00 0.20 0.00 0.20 - kworker/u4:1
Average: 0 18691 0.20 0.00 0.00 0.20 - irqbalance
Average: 0 18778 0.00 0.20 0.00 0.20 - kworker/1:2
Average: 1001 32703 0.00 0.20 0.00 0.20 - java
可以看到,stress进程导致了cpu升高。
4.3 多进程场景
还有一种场景就是进程数量过多。现在通过stress模拟。 终端1中:
[root@m162p201 ~]# stress -c 8 --timeout 600
stress: info: [15557] dispatching hogs: 8 cpu, 0 io, 0 vm, 0 hdd
现在由于只有2个CPU,而进程数量大于2,显然会导致系统负载上升。 终端2中:
uptime截图
可以看到1分钟的负载变成了7.62 我们再通过pidstat来分析。 终端3中: mpstat
[root@m162p201 ~]# mpstat -P ALL 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
07:38:44 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
07:38:49 PM all 99.70 0.00 0.20 0.00 0.00 0.10 0.00 0.00 0.00 0.00
07:38:49 PM 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:38:49 PM 1 99.80 0.00 0.20 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 99.70 0.00 0.20 0.00 0.00 0.10 0.00 0.00 0.00 0.00
Average: 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: 1 99.80 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00
[root@m162p201 ~]#
pidstat
[root@m162p201 ~]# pidstat -u 5 1
Linux 3.10.0-514.el7.x86_64 (m162p201) 07/13/2021 _x86_64_ (2 CPU)
07:37:54 PM UID PID %usr %system %guest %CPU CPU Command
07:37:59 PM 1008 8031 0.20 0.00 0.00 0.20 1 java
07:37:59 PM 1007 10589 0.20 0.20 0.00 0.40 1 java
07:37:59 PM 0 15558 24.60 0.00 0.00 24.60 0 stress
07:37:59 PM 0 15559 24.40 0.00 0.00 24.40 0 stress
07:37:59 PM 0 15560 24.60 0.00 0.00 24.60 0 stress
07:37:59 PM 0 15561 24.60 0.00 0.00 24.60 1 stress
07:37:59 PM 0 15562 24.60 0.00 0.00 24.60 1 stress
07:37:59 PM 0 15563 25.00 0.00 0.00 25.00 1 stress
07:37:59 PM 0 15564 25.00 0.00 0.00 25.00 0 stress
07:37:59 PM 0 15565 24.60 0.00 0.00 24.60 1 stress
07:37:59 PM 0 15571 0.00 0.20 0.00 0.20 1 watch
07:37:59 PM 0 18040 0.40 0.20 0.00 0.60 0 etcd
07:37:59 PM 0 18778 0.00 0.20 0.00 0.20 1 kworker/1:2
07:37:59 PM 1001 32703 0.20 0.00 0.00 0.20 1 java
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 1008 8031 0.20 0.00 0.00 0.20 - java
Average: 1007 10589 0.20 0.20 0.00 0.40 - java
Average: 0 15558 24.60 0.00 0.00 24.60 - stress
Average: 0 15559 24.40 0.00 0.00 24.40 - stress
Average: 0 15560 24.60 0.00 0.00 24.60 - stress
Average: 0 15561 24.60 0.00 0.00 24.60 - stress
Average: 0 15562 24.60 0.00 0.00 24.60 - stress
Average: 0 15563 25.00 0.00 0.00 25.00 - stress
Average: 0 15564 25.00 0.00 0.00 25.00 - stress
Average: 0 15565 24.60 0.00 0.00 24.60 - stress
Average: 0 15571 0.00 0.20 0.00 0.20 - watch
Average: 0 18040 0.40 0.20 0.00 0.60 - etcd
Average: 0 18778 0.00 0.20 0.00 0.20 - kworker/1:2
Average: 1001 32703 0.20 0.00 0.00 0.20 - java
可以看出,user的cpu上升,而这些cpu的上升都是stress进程过多所致。这超出了当前系统的计算能力。
5 总结
通过本文学习,我们需要知道,平均负载是一个快速查看系统整体性能的手段。但是只通过这一个参数,我们很难发现系统的问题,我们需要结合cpu数量,以及其他的系统监控指标共同做出判断。 CPU密集型和IO密集型都可能导致平均负载升高。而系统的平均负载升高,则需要结合相关的工具如mpstat和pidstat来综合判断。 最后,再总结一下平均负载的概念,表示单位时间内系统的活跃进程数量(包括R状态和D状态的进程)。
|