基础:什么是平均负载

uptime

每次发现系统变慢时,我们通常做的第一件事情,就是执行top或者uptime命令,来了解系统的负载情况,比如:

oceanstar@oceanstar:~$ uptime
 22:59:50 up 3 min,  1 user,  load average: 0.96, 0.95, 0.42
  • 当前时间 : 22:59:50
  • 系统已运行的时间: up 3 min
  • 当前在线用户: 1 user
  • 平均负载: 0.96, 0.95, 0.42,最近1分钟、5分钟、15分钟系统的平均负载( load average)

平均负载可以说是最常见,也是最重要的系统指标。那么什么是平均负载呢?

什么是平均负载

平均负载,是指单位时间内,系统处于可运行状态不可中断状态的平均进程树,也就是平均活跃进程数,他和CPU使用率并没有直接关系

  • 所谓可运行状态的进程,是指正在使用CPU和正在等待CPU的进程,也就是ps命令看到的,处于R状态(Running、Runnable)的进程
  • 所谓不可中断状态的进程,是指正处于内核态关键流程,并且这些流程是不可打断的
    • 比如最常见的是等待硬件设备的IO响应,也就是ps命令看到的处于D状态(Uninterruptible Sleep,也称为Disk Sleep)的进程
    • 比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断的,这个时候的进程就处于不可中断的状态。如果此时的进程被打断了,就容易出现磁盘数据和进程数据不一致的情况。
    • 所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制

因此,你可以理解为,平均负载其实就是平均活跃进程数。平均活跃进程数,直观上的理解就是单位时间内的活跃进程数,但它实际上是活跃进程数的指数衰减平均值。这个“指数衰减平均”的详细含义不用去计较,这只是系统的一种更快速的计算方式,把它直接当初活跃进程数的平均值即可。

既然平均的是活跃进程数量,那么最理想的是,每个CPU上都刚好运行着一个进程,这样每个CPU都得到了充分利用。比如,当平均负载为2时,意味着什么呢?

  • 在只有2个CPU的系统上,意味着所有的CPU都刚好被完全占用
  • 在4个CPU的系统上,意味着CPU有50%的空闲
  • 在只有1个CPU的系统上,意味着有一半的进程竞争不到CPU

平均负载为多少时合理

问题是:怎么判断出,在uptime命令的结果里,那三个时间段的平均负载数,多大的时候能说明系统负载高?多小的时候能说明系统负责很低呢?

我们知道,平均负载最理想的情况是等于CPU个数。所以在评判瓶颈负载的时候,第一步是需要知道系统有几个CPU,这可以通过top命令或者从/proc/cpuinfo中读取,比如:

$ grep 'model name' /proc/cpuinfo | wc -l
4

有了CPU个数,我们就能判断出,当平均负载比CPU个数大的时候,系统已经出现了过载

第二个问题:平均负载有三个值,到底应该参考哪一个呢?

实际上,都要看。打个⽐⽅,就像初秋时北京的天⽓,如果只看中午的温度,你可能以为还在7⽉份的⼤夏天呢。但如果你结合了早上、中午、晚上三个时间点的温度来看,基本就可以全⽅位了解这⼀天的天⽓情况了

这上不同时间间隔的平均值,可以让我们分析系统负载趋势

  • 如果1分钟、5分钟、15分钟的三个值基本相同,或者相差不⼤,那就说明系统负载很平稳。
  • 但如果1分钟的值远⼩于15 分钟的值,就说明系统最近1分钟的负载在减少,⽽过去15分钟内却有很⼤的负载。
  • 反过来,如果1分钟的值远⼤于 15 分钟的值,就说明最近1分钟的负载在增加,这种增加有可能是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦1分钟的平均负载接近或者超过了CPU的个数,就意味着系统正在发生过载的问题,这时就得分析调查是哪里导致的问题,并要想办法优化

举个例子,假设我们在一个单CPU系统上看到平均负载为1.73、0.60、7.98,那么说明在过去1分钟内,系统有73%的超载,而在15分钟内,有698%的超载,从整体趋势来看,系统的负载在降低。

第三个问题:在实际生成环境中,平均负载多高时,需要我们中断关注呢?

当平均负载高于CPU数量70%的时候,你就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能

但70%这个数字并不是绝对的,最推荐的⽅法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化
趋势。当发现负载有明显升⾼趋势时,⽐如说负载翻倍了,你再去做分析和调查。

平均负载 VS CPU使用率

  • 平均负载是指单位时间内,出于可运行状态和不可中断状态的进程数。所以,它不仅包括正在使用CPU的进程,还包括等待CPU等待IO的进程
  • CPU使用率,是指单位时间内CPU繁忙时间的统计,跟平均负载不一定完全对应,比如:
    • CPU密集型进程,使用大量CPU会导致平均负载升高,此时这两者是一致的
    • IO密集型进程,等待IO也会导致平均负载升高,但CPU使用率不一定很高
    • 大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高

案例

下⾯,我们以三个示例分别来看这三种情况,并⽤ iostat、mpstat、pidstat 等⼯具,找出平均负载升⾼的根源。

准备

  • 机器配置:4 CPU,8GB 内存
  • 预先安装 stress 和 sysstat 包,如 apt install stress sysstat。
    • stress:是一个Linyx系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景
    • sysstat包含了常用的Linux性能⼯具,⽤来监控和分析系统的性能。我们的案例会⽤到这个包的两个命令 mpstat 和pidstat。
      • mpstat 是⼀个常⽤的多核 CPU 性能分析⼯具,⽤来实时查看每个 CPU 的性能指标,以及所有CPU的平均指标。
      • pidstat是⼀个常⽤的进程性能分析⼯具,⽤来实时查看进程的 CPU、内存、I/O 以及上下⽂切换等性能指标

此外,每个场景都需要你开三个终端,登录到同⼀台 Linux 机器中。

另外要注意,下⾯的所有命令,我们都是默认以 root ⽤户运⾏。

如果上⾯的要求都已经完成了,你可以先⽤ uptime 命令,看⼀下测试前的平均负载情况:

$ uptime
... load average: 0.04, 0.02, 0.00

场景一:CPU密集型进程

⾸先,我们在第⼀个终端运⾏ stress 命令,模拟⼀个 CPU 使⽤率 100% 的场景:

# --cpu 1: 指的是测试1个cpu --- 产生1个进程 每个进程都反复不停的计算随机数的平方根
# -t --timeout 600 : 指定运行600秒后停止
# stress测试cpu,是在用户态将cpu 耗尽。
$ stress --cpu 1 --timeout 600
stress: info: [3629] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd

接着,在第⼆个终端运⾏uptime查看平均负载的变化情况:

# -d 参数表示⾼亮显示变化的区域
$ watch -d uptime
..., load average: 1.00, 0.75, 0.39

最后,在第三个终端运⾏mpstat查看 CPU 使⽤率的变化情况:

# -P ALL 表示监控所有CPU,后⾯数字5表示间隔5秒后输出⼀组数据
$ mpstat -P ALL 5
Linux 5.8.0-48-generic (oceanstar) 	20211020_x86_64_	(4 CPU)

235858秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
235903秒  all   25.15    0.00    0.00    0.00    0.00    0.05    0.00    0.00    0.00   74.80
2359030    0.00    0.00    0.00    0.00    0.00    0.20    0.00    0.00    0.00   99.80
2359031  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
2359032    0.80    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.20
2359033    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

从终端二可以看到,1分钟的平均负载会慢慢增加到1.00,而从终端三中还可以看到,正好有一个CPU的使用率为100%,但是它的iowait只有0。这说明,平均负载的升高正是由于CPU使用率为100%

那么,到底是哪个进程导致了 CPU 使⽤率为 100% 呢?你可以使⽤ pidstat来查询:

# 间隔5s后输出一组数据,-u表示CPU指标
$ pidstat -u 5 1
Linux 5.8.0-48-generic (oceanstar) 	20211021_x86_64_	(4 CPU)

192826秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
1928310       679    0.00    0.20    0.00    0.00    0.20     3  vmtoolsd
1928311000      2187    0.40    1.00    0.00    0.40    1.40     3  Xorg
1928311000      2318    1.20    0.80    0.00    0.20    2.00     1  gnome-shell
1928311000      2659    0.60    0.20    0.00    0.20    0.80     3  gnome-terminal-
1928310      8133    0.20    0.00    0.00    0.00    0.20     1  mpstat
1928310      8153  100.00    0.00    0.00    0.00  100.00     2  stress
1928311000      8231    0.00    0.20    0.00    0.00    0.20     0  pidstat

平均时间:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
平均时间:     0       679    0.00    0.20    0.00    0.00    0.20     -  vmtoolsd
平均时间:  1000      2187    0.40    1.00    0.00    0.40    1.40     -  Xorg
平均时间:  1000      2318    1.20    0.80    0.00    0.20    2.00     -  gnome-shell
平均时间:  1000      2659    0.60    0.20    0.00    0.20    0.80     -  gnome-terminal-
平均时间:     0      8133    0.20    0.00    0.00    0.00    0.20     -  mpstat
平均时间:     0      8153  100.00    0.00    0.00    0.00  100.00     -  stress
平均时间:  1000      8231    0.00    0.20    0.00    0.00    0.20     -  pidstat

从这里可以明显看到,stress进程的CPU使用率为100%

场景二:IO密集型进行

首先开始运行stress命令,但这次模拟IO压力,即不停的执行sync:

$ stress -i 1 --timeout 600
stress: info: [8830] dispatching hogs: 0 cpu, 1 io, 0 vm, 0 hdd

还是在第二个终端指针uptime查看平均负载的变化情况:

$ watch -d uptime
 load average: 1.06, 0.90, 0.64

然后在第三个终端运行upstat查看CPU使用率变化情况:

# -P ALL 表示监控所有CPU,后⾯数字5表示间隔5秒后输出⼀组数据
$ mpstat -P ALL 5
19时38分29秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
19时38分34秒  all    1.30    0.00   24.96    0.00    0.00    0.00    0.00    0.00    0.00   73.73
19时38分34秒    0    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00   99.80
19时38分34秒    1    0.81    0.00    0.81    0.00    0.00    0.00    0.00    0.00    0.00   98.39
19时38分34秒    2    3.41    0.00   96.39    0.00    0.00    0.00    0.00    0.00    0.00    0.20
19时38分34秒    3    1.00    0.00    2.40    0.00    0.00    0.00    0.00    0.00    0.00   96.61

从这⾥可以看到,1 分钟的平均负载会慢慢增加到 1.06,其中⼀个 CPU 的系统CPU使⽤率升⾼到了 96.39 ,疑惑:为什么这里的iowait还是0,感觉这次CPU的升高是由于系统调用引起的????????

回答:

  • iowait无法升高的问题:是因为stress使用的是sync()系统调用,它的作用是刷新缓冲区内存到磁盘中。对于新安装的虚拟机,缓冲区可能比较小,无法产生大的IO压力,这样大部分就是系统调用的消耗了,所以你会看到只有系统CPU使用率升高。
  • 解决方法:使用stress的下一代stress-ng,它支持更丰富的选项,比如stress-ng -i --hdd 1 --tiimeout 600 (–hdd表示读写临时文件)

看一下到底是哪个进程导致了CPU使用率急剧上升:

# 间隔5s后输出一组数据,-u表示CPU指标
$ pidstat -u 5 1
Linux 5.8.0-48-generic (oceanstar) 	2021年10月21日 	_x86_64_	(4 CPU)

19时41分28秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
19时41分33秒     0       679    0.20    0.00    0.00    0.00    0.20     3  vmtoolsd
19时41分33秒  1000      2187    0.00    0.40    0.00    0.00    0.40     0  Xorg
19时41分33秒  1000      2318    0.40    0.40    0.00    0.40    0.80     1  gnome-shell
19时41分33秒  1000      2470    0.00    0.20    0.00    0.00    0.20     3  vmtoolsd
19时41分33秒  1000      2659    0.00    0.20    0.00    0.20    0.20     0  gnome-terminal-
19时41分33秒     0      2898    0.00    0.20    0.00    0.00    0.20     2  kworker/2:1-events
19时41分33秒     0      8831    3.59   96.21    0.00    0.00   99.80     2  stress
19时41分33秒  1000      9422    0.00    0.20    0.00    0.00    0.20     1  pidstat

平均时间:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
平均时间:     0       679    0.20    0.00    0.00    0.00    0.20     -  vmtoolsd
平均时间:  1000      2187    0.00    0.40    0.00    0.00    0.40     -  Xorg
平均时间:  1000      2318    0.40    0.40    0.00    0.40    0.80     -  gnome-shell
平均时间:  1000      2470    0.00    0.20    0.00    0.00    0.20     -  vmtoolsd
平均时间:  1000      2659    0.00    0.20    0.00    0.20    0.20     -  gnome-terminal-
平均时间:     0      2898    0.00    0.20    0.00    0.00    0.20     -  kworker/2:1-events
平均时间:     0      8831    3.59   96.21    0.00    0.00   99.80     -  stress
平均时间:  1000      9422    0.00    0.20    0.00    0.00    0.20     -  pidstat

从上面可以看到,还是因为stress

场景三:大量进程的场景

当系统中运行进程超出CPU运行能力时,就会出现等待CPU的进程

首先开始运行stress命令,但这次模拟了16个进程:

$ stress -c 16 --timeout 600
stress: info: [10197] dispatching hogs: 16 cpu, 0 io, 0 vm, 0 hdd

由于系统只有4个CPU,明显比16个进程要少得多。因此,系统的CPU处于严重过载的状态(6.67):

$ uptime
 19:50:26 up  1:47,  1 user,  load average: 6.67, 2.08, 1.13
# mpstat -P ALL 5
Linux 5.8.0-48-generic (oceanstar) 	2021年10月21日 	_x86_64_	(4 CPU)

19时51分03秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
19时51分08秒  all   98.88    0.00    1.02    0.00    0.00    0.10    0.00    0.00    0.00    0.00
19时51分08秒    0   98.38    0.00    1.62    0.00    0.00    0.00    0.00    0.00    0.00    0.00
19时51分08秒    1   98.98    0.00    0.82    0.00    0.00    0.20    0.00    0.00    0.00    0.00
19时51分08秒    2   99.19    0.00    0.81    0.00    0.00    0.00    0.00    0.00    0.00    0.00
19时51分08秒    3   98.99    0.00    0.81    0.00    0.00    0.20    0.00    0.00    0.00    0.00

接在运行pidstat查看进程的情况:

# 间隔5s后输出一组数据,-u表示CPU指标
$ pidstat -u 5 1
Linux 5.8.0-48-generic (oceanstar) 	2021年10月21日 	_x86_64_	(4 CPU)

19时51分46秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
19时51分51秒     0        11    0.00    0.20    0.00    0.00    0.20     0  rcu_sched
19时51分51秒     0       679    0.20    0.00    0.00    0.00    0.20     1  vmtoolsd
19时51分51秒  1000      2187    0.80    4.38    0.00    0.60    5.18     3  Xorg
19时51分51秒  1000      2318    0.40    0.80    0.00    1.99    1.20     3  gnome-shell
19时51分51秒  1000      2659    0.60    3.59    0.00    0.00    4.18     0  gnome-terminal-
19时51分51秒     0     10198   23.90    0.00    0.00   75.90   23.90     1  stress
19时51分51秒     0     10199   23.90    0.20    0.00   76.10   24.10     0  stress
19时51分51秒     0     10200   23.51    0.40    0.00   75.70   23.90     0  stress
19时51分51秒     0     10201   23.51    0.20    0.00   75.90   23.71     2  stress
19时51分51秒     0     10202   25.30    0.40    0.00   74.30   25.70     3  stress
19时51分51秒     0     10203   31.08    0.20    0.00   68.33   31.27     1  stress
19时51分51秒     0     10204   22.71    0.00    0.00   76.69   22.71     1  stress
19时51分51秒     0     10205   23.11    0.80    0.00   76.10   23.90     0  stress
19时51分51秒     0     10206   28.49    0.40    0.00   70.72   28.88     3  stress
19时51分51秒     0     10207   22.31    0.20    0.00   77.49   22.51     1  stress
19时51分51秒     0     10208   22.51    0.40    0.00   77.49   22.91     3  stress
19时51分51秒     0     10209   23.90    0.20    0.00   76.10   24.10     3  stress
19时51分51秒     0     10210   22.71    0.40    0.00   76.89   23.11     2  stress
19时51分51秒     0     10211   22.31    0.00    0.00   77.49   22.31     2  stress
19时51分51秒     0     10212   22.11    0.40    0.00   77.29   22.51     0  stress
19时51分51秒     0     10213   22.71    0.00    0.00   77.29   22.71     2  stress
19时51分51秒  1000     10219    0.00    0.20    0.00    0.00    0.20     1  pidstat

可以看出,16个进程在争抢4个CPU,每个进程等待CPU的时间(%wait列)高达75%。这些超出CPU计算能力的进程,最终导致CPU过载

pidstat输出中没有%wait的问题:

  • 因为centos默认的sysstat稍微有点老,源码或者RPM升级到11.5.5版本之后就可以看到了。
  • 而unbuntu中的包一般都比较新,没有这个问题

mpstat无法观测的问题:

  • 案例中是等待5s后输出1次结果就停止了,更好的做法是持续监控一段时间,比如持续观测20次: mpstat -P ALL 5 20

总结

平均负载提供了一个快速查看系统整体性能的手段,反映了整体的负载情况。但只看平均负载本身,我们并不能直接发现,到底是哪里出了问题。所以,在理解平均负载时,也要注意:

  • 平均负载高有可能是CPU密集型进程导致的
  • 平均负载高并不一定代码CPU使用率高,还可能是IO更繁忙了
  • 当发现负载高的时候,你可以使用mpstat、pidstat等工具,辅助分析负载的来源

其他

mpstat

语法:

mpstat [-P {cpu|ALL}] [internal [count]]

其中,各参数含义如下:

参数 含义
-P {cpu l ALL} 表示监控哪个CPU, cpu在[0,cpu个数-1]中取值
internal 相邻的两次采样的间隔时间
count 采样的次数,count只能和delay一起使用

输出参数含义

参数 释义 从/proc/stat获得数据
CPU 处理器ID
%usr 在internal时间段里,用户态的CPU时间(%),不包含 nice值为负进程 usr/total*100
%nice 在internal时间段里,nice值为负进程的CPU时间(%) nice/total*100
%sys 在internal时间段里,核心时间(%) system/total*100
%iowait 在internal时间段里,硬盘IO等待时间(%) iowait/total*100
%irq 在internal时间段里,硬中断时间(%) irq/total*100
%soft 在internal时间段里,软中断时间(%) softirq/total*100
%steal 显示虚拟机管理器在服务另一个虚拟处理器时虚拟CPU处在非自愿等待下花费时间的百分比 steal/total*100
%guest 显示运行虚拟处理器时CPU花费时间的百分比 guest/total*100
%gnice gnice/total*100
%idle 在internal时间段里,CPU除去等待磁盘IO操作外的因为任何原因而空闲的时间闲置时间(%) idle/total*100

CPU总的工作时间:

total_cur = user + system + nice + idle + iowait + irq + softirq

total_pre = pre_user + pre_system + pre_nice + pre_idle + pre_iowait + pre_irq + pre_softirq

user = user_cur – user_pre

total = total_cur - total_pre

其中_cur 表示当前值,_pre表示interval时间前的值。上表中的所有值可取到两位小数点。

实例

直接使用mpstat命令:

mpstat   #当mpstat不带参数时,输出为从系统启动以来的平均值。

在这里插入图片描述

mpstat -P ALL 5 2   #表示每5秒产生一个报告,总共产生2个

基础:什么是平均负载_第1张图片
上图表示每5秒产生了2个关于处理器的统计数据报告,一共产生2个interval 的信息,然后再给出这2个interval的平均信息。默认时,输出是按照CPU 号排序。第一个行给出了从系统引导以来的所有活跃数据。接下来每行对应一个处理器的活跃状态。

你可能感兴趣的:(计算机理论与基础,linux)