linux之平均负载(学习笔记非原创)

什么是平均负载

[root@111 ~]# uptime
 11:03:33 up 149 days, 17:34,  1 user,  load average: 0.08, 0.05, 0.01

最后三个数字,依次则是过去1分钟、5分钟、15分钟的平均负载(Load Average),常用的top工具也能展示

平均负载作为极其重要的系统指标,是指单位时间内,系统处于可运行状态不可中断状态的平均进程数,也就是平均活跃进程数,它和CPU使用率并没有直接关系。

可运行状态的进程,是指正在使用CPU或者正在等待CPU的进程,也就是我们常用ps命令看到的,处于R状态(Running 或 Runnable)的进程。

不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的I/O响应,也就是我们在ps命令中看到的D状态(Uninterruptible Sleep)的进程。

比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。

所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

综上所述,平均负载其实就是平均活跃进程数,即单位时间内的活跃进程数。

平均负载为多少时合理

最理想的状态,是每个CPU上都刚好跑着一个进程,这样每个CPU都得到了充分利用。比如当平均负载为2时,意味着什么呢?

  • 在只有2个CPU的系统上,意味着所有的CPU都刚好被完全占用。

  • 在4个CPU的系统上,意味着CPU有50%的空闲。

  • 而在只有1个CPU的系统中,则意味着有一半的进程竞争不到CPU。

所以,平均负载最理想的情况是等于 CPU个数。在评判平均负载时,首先要知道系统有几个 CPU,可以通过 top 命令或者从文件 /proc/cpuinfo 中读取,比如:

逻辑cpu个数:
[root@111 ~]# grep processor /proc/cpuinfo |wc -l
4

一般来说,实际生产环境中,当平均负载为 CPU 数量的70-80%的时候,就应该分析排查负载高的问题了。

另一方面,我们需要关注平均负载三个数值的变化:

  • 如果1分钟、5分钟、15分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。

  • 但如果1分钟的值远小于15 分钟的值,就说明系统最近1分钟的负载在减少,而过去15分钟内却有很大的负载。

  • 反过来,如果1分钟的值远大于 15 分钟的值,就说明最近1分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦1分钟的平均负载接近或超过了CPU的个数,就意味着系统正在发生过载的问题,这时就得分析调查是哪里导致的问题,并要想办法优化了。

举个栗子,4核的机子,平均负载为 3.23,1.60,6.98:

  • 在过去的15分钟,平均负载超过cpu个数,说明负载很高,可能是cpu使用率很高,也可能是I/O的压力等等原因。
  • 过去1分钟和过去5分钟,平均负载都小于cpu个数,说明负载正常,从整体趋势来看,系统的负载在降低,但是过去1分钟的值大于过去5分钟的值,说明平均负载又在升高。

70-80%这个数字并不是绝对的,毕竟最长的15分钟的数据也只是短期的表现,最推荐的方法,是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的整体变化趋势。

平均负载与CPU使用率

现实工作中,我们经常容易把平均负载和 CPU 使用率混淆,其实两者还是有区别的。

可能你会疑惑,既然平均负载代表的是活跃进程数,那平均负载高了,不就意味着 CPU 使用率高吗?

我们还是要回到平均负载的含义上来,平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。

CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:

  • CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;

  • I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;

  • 大量等待 CPU 的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高。

平均负载案例模拟分析

模拟三个场景分别来看以上三种情况,使用iostat、mpstat、pidstat 等工具,找出平均负载升高的根源。

  • 机器配置:4cpu,16G内存,centos
  • 安装 stress 和 sysstat 工具包,yum install stress sysstat -y

stress 是一个 Linux 系统压力测试工具

stress语法格式:
stress <options>

常用选项:
-c, --cpu N              产生 N 个进程,每个进程都反复不停的计算随机数的平方根
-i, --io N               产生 N 个进程,每个进程反复调用 sync() 将内存上的内容写到硬盘上
-m, --vm N               产生 N 个进程,每个进程不断分配和释放内存
    --vm-bytes B         指定分配内存的大小
    --vm-stride B        不断的给部分内存赋值,让 COW(Copy On Write)发生
    --vm-hang N          指示每个消耗内存的进程在分配到内存后转入睡眠状态 N 秒,然后释放内存,一直重复执行这个过程
    --vm-keep            一直占用内存,区别于不断的释放和重新分配(默认是不断释放并重新分配内存)
-d, --hadd N             产生 N 个不断执行 writeunlink 函数的进程(创建文件,写入内容,删除文件)
    --hadd-bytes B       指定文件大小
-t, --timeout N          在 N 秒后结束程序        
--backoff N              等待N微妙后开始运行
-q, --quiet              程序在运行的过程中不输出信息
-n, --dry-run            输出程序会做什么而并不实际执行相关的操作
--version                显示版本号
-v, --verbose            显示详细的信息

sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能,主要包括:

iostat 工具提供CPU使用率及硬盘吞吐效率的数据;  #比较核心的工具
mpstat 工具提供单个处理器或多个处理器相关数据;
pidstat: 关于运行中的进程/任务、CPU、内存等的统计信息
sar 工具负责收集、报告并存储系统活跃的信息;    #统计数据的核心工具
sa1 工具负责收集并存储每天系统动态信息到一个二进制的文件中。它是通过计划任务工具cron来运行,是为sadc所设计的程序前端程序;
sa2工具负责把每天的系统活跃性息写入总结性的报告中。它是为sar所设计的前端 ,要通过cron来调用
sadc 是系统动态数据收集工具,收集的数据被写一个二进制的文件中,它被用作sar工具的后端;
sadf 显示被sar通过多种格式收集的数据;
nfsiostat: NFS(Network File System)的I/O统计信息。
cifsiostat: CIFS(Common Internet File System)的统计信息。

每个场景都需要开三个终端,登录到同一台 Linux 机器中,使用uptime看一下测试前的平均负载:

[root@123~]# uptime 
 16:11:04 up 150 days, 22:42,  3 users,  load average: 0.06, 0.03, 0.00

场景一:CPU 密集型进程

首先,在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:

#产生1个进程反复不停的计算随机数的平方根,300秒后停止
[root@123 ~]# stress -c 1 -t 300

接着,在第二个终端运行watch -d uptime查看平均负载的变化情况:

# -d 参数表示高亮显示变化的区域
Every 2.0s: uptime 
16:26:55 up 150 days, 22:58, 3 users, load average: 1.05, 0.76, 0.40

可以看到,1 分钟的平均负载会慢慢增加到 1.00出头

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

mpstat --help
用法: mpstat [ 选项 ] [ <时间间隔> [ <次数> ] ]
选项:
[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]
[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <CPU_列表> | ALL } ]

#-P ALL 表示监控所有CPU,间隔5秒后输出一组数据,总计5组
[root@123~]# mpstat -P ALL 5 5

04:25:28 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
04:25:33 PM  all   25.11    0.00    0.20    0.35    0.00    0.00    0.00    0.00   74.34
04:25:33 PM    0    0.40    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.40
04:25:33 PM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
04:25:33 PM    2    0.00    0.00    0.60    1.60    0.00    0.00    0.00    0.00   97.80
04:25:33 PM    3    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.80

04:25:33 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
04:25:38 PM  all   25.13    0.00    0.15    0.40    0.00    0.00    0.00    0.00   74.32
04:25:38 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
04:25:38 PM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
04:25:38 PM    2    0.20    0.00    0.40    1.41    0.00    0.00    0.00    0.00   97.99
04:25:38 PM    3    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

可以看到,正好有一个 CPU 的使用率为 100%,但它的 iowait 只有 0。这说明,平均负载的升高正是由于 CPU 使用率为 100% 

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

pidstat --help
用法:pidstat [ 选项 ] [ <时间间隔> [ <计数> ] ] [ -e <程序> <参数> ]
选项:
[ -d ] [ -H ] [ -h ] [ -I ] [ -l ] [ -R ] [ -r ] [ -s ] [ -t ] [ -U [ <用户名> ] ]
[ -u ] [ -V ] [ -v ] [ -w ] [ -C <命令> ] [ -G <进程名> ]
[ -p { <pid> [,...] | SELF | ALL } ] [ -T { TASK | CHILD | ALL } ]
[ --dec={ 0 | 1 | 2 } ] [ --human ]
常用选项解释:
-u:默认的参数,显示各个进程的cpu使用统计
-r:显示各个进程的内存使用统计
-d:显示各个进程的IO使用情况
-p:指定进程号
-w:显示每个进程的上下文切换情况

#间隔5秒输出一组数据,总计5组
[root@123 ~]# pidstat -u 5 5

04:26:17 PM       PID    %usr %system  %guest    %CPU   CPU  Command
04:26:22 PM      2464    0.20    0.00    0.00    0.20     3  netdata
04:26:22 PM      2677    0.20    0.00    0.00    0.20     0  python
04:26:22 PM     26629    0.00    0.40    0.00    0.40     2  apps.plugin
04:26:22 PM     28735  100.00    0.00    0.00  100.00     3  stress

04:26:22 PM       PID    %usr %system  %guest    %CPU   CPU  Command
04:26:27 PM      2464    0.20    0.00    0.00    0.20     3  netdata
04:26:27 PM     26629    0.20    0.20    0.00    0.40     2  apps.plugin
04:26:27 PM     28735  100.00    0.00    0.00  100.00     3  stress

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

场景二:I/O 密集型进程

首先还是运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync:

# 产生1个进程,反复调用 sync() 将内存上的内容写到硬盘上,300秒后结束
[root@123~]# stress -i 1 -t 300

还是在第二个终端运行watch -d uptime查看平均负载的变化情况:

17:14:02 up 150 days, 23:45,  4 users,  load average: 1.52, 1.68, 0.80

可以看到,平均负载再次上升

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

#显示所有CPU的指标,间隔5秒输出一组数据,持续输出
[root@123 ~]# mpstat -P ALL 5
05:08:10 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:08:15 PM  all    0.15    0.00    0.15    0.20    0.00    0.00    0.00    0.00   99.50
05:08:15 PM    0    0.20    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.60
05:08:15 PM    1    0.20    0.00    0.40    0.00    0.00    0.00    0.00    0.00   99.40
05:08:15 PM    2    0.20    0.00    0.00    1.00    0.00    0.00    0.00    0.00   98.80
05:08:15 PM    3    0.20    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.60

05:08:15 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:08:20 PM  all    0.15    0.00    0.20   10.67    0.00    0.00    0.00    0.00   88.98
05:08:20 PM    0    0.20    0.00    0.00   14.63    0.00    0.00    0.00    0.00   85.17
05:08:20 PM    1    0.00    0.00    0.40    0.00    0.00    0.00    0.00    0.00   99.60
05:08:20 PM    2    0.00    0.00    0.20   28.11    0.00    0.00    0.00    0.00   71.69
05:08:20 PM    3    0.20    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.80

05:08:20 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:08:25 PM  all    0.15    0.00    0.20   22.19    0.00    0.00    0.00    0.00   77.45
05:08:25 PM    0    0.20    0.00    0.20   29.46    0.00    0.00    0.00    0.00   70.14
05:08:25 PM    1    0.20    0.00    0.40    0.00    0.00    0.00    0.00    0.00   99.40
05:08:25 PM    2    0.20    0.00    0.20   59.44    0.00    0.00    0.00    0.00   40.16
05:08:25 PM    3    0.20    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.60

可以发现,系统CPU使用率很低,而 iowait很高,其中一个高达 59.44%,这说明平均负载的升高是由于 iowait 的升高。

是哪个进程导致iowait这么高?

#pidstat -d:显示各个进程的IO使用情况
[root@123 ~]# pidstat -d 3 3

05:12:56 PM       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
05:12:59 PM       701      0.00     68.00      0.00  jbd2/dm-0-8
05:12:59 PM      1518      0.00    292.00      0.00  flush-253:0
05:12:59 PM      1968      0.00     28.00      0.00  java

05:12:59 PM       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
05:13:02 PM       701      0.00     80.00      0.00  jbd2/dm-0-8
05:13:02 PM      1518      0.00    268.00      0.00  flush-253:0
05:13:02 PM      1968      0.00     30.67      0.00  java

05:13:02 PM       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
05:13:05 PM       701      0.00     80.00      0.00  jbd2/dm-0-8
05:13:05 PM      1518      0.00    286.67      0.00  flush-253:0
05:13:05 PM      1968      0.00     36.00      0.00  java

jbd2/dm-0-8和flush-253:0都是操作系统针对磁盘和文件系统的进程,本质上是stress 进程导致的,因为300秒后当stress结束了,这两个进程也结束了。

场景三:大量进程的场景

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

比如,我们还是使用 stress,但这次模拟的是 8 个进程:

[root@123 ~]# stress -c 8 -t 300

由于系统只有 4 个CPU,比 8 个进程要少一半,因而,系统的 CPU 处于严重过载状态,平均负载高达7.90:

11:35:53 up 155 days, 18:07,  4 users,  load average: 7.90, 5.51, 3.00

使用mpstat查看cpu使用率

[root@123~]# mpstat -P ALL 3 10

11:30:17 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
11:30:20 AM  all   99.83    0.00    0.17    0.00    0.00    0.00    0.00    0.00    0.00
11:30:20 AM    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
11:30:20 AM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
11:30:20 AM    2  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
11:30:20 AM    3   99.67    0.00    0.33    0.00    0.00    0.00    0.00    0.00    0.00

11:30:20 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
11:30:23 AM  all   99.92    0.00    0.08    0.00    0.00    0.00    0.00    0.00    0.00
11:30:23 AM    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
11:30:23 AM    1   99.67    0.00    0.33    0.00    0.00    0.00    0.00    0.00    0.00
11:30:23 AM    2   99.67    0.00    0.33    0.00    0.00    0.00    0.00    0.00    0.00
11:30:23 AM    3  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00

可见4个cpu都被打满,再用pidstat看一下进程使用cpu的情况:

[root@123 ~]# pidstat 3 10

11:30:20 AM       PID    %usr %system  %guest    %CPU   CPU  Command
11:30:23 AM      2385    0.33    0.00    0.00    0.33     2  java
11:30:23 AM      2464    0.33    0.33    0.00    0.66     0  netdata
11:30:23 AM     26384   49.67    0.00    0.00   49.67     1  stress
11:30:23 AM     26385   49.67    0.00    0.00   49.67     0  stress
11:30:23 AM     26386   49.01    0.00    0.00   49.01     3  stress
11:30:23 AM     26387   49.67    0.00    0.00   49.67     2  stress
11:30:23 AM     26388   50.66    0.00    0.00   50.66     3  stress
11:30:23 AM     26389   49.67    0.00    0.00   49.67     0  stress
11:30:23 AM     26390   49.67    0.00    0.00   49.67     1  stress
11:30:23 AM     26391   49.67    0.00    0.00   49.67     2  stress

11:30:23 AM       PID    %usr %system  %guest    %CPU   CPU  Command
11:30:26 AM     26223    0.33    0.00    0.00    0.33     3  watch
11:30:26 AM     26384   49.67    0.00    0.00   49.67     1  stress
11:30:26 AM     26385   50.00    0.00    0.00   50.00     0  stress
11:30:26 AM     26386   50.00    0.00    0.00   50.00     3  stress
11:30:26 AM     26387   50.00    0.00    0.00   50.00     2  stress
11:30:26 AM     26388   49.67    0.00    0.00   49.67     3  stress
11:30:26 AM     26389   50.00    0.00    0.00   50.00     0  stress
11:30:26 AM     26390   50.00    0.00    0.00   50.00     1  stress
11:30:26 AM     26391   50.00    0.00    0.00   50.00     2  stress
11:30:26 AM     26524    0.00    0.33    0.00    0.33     2  pidstat

可以看出,8 个stress进程在争抢 4 个 CPU,每个进程都占据着0.5个cpu,同时等待 CPU 的时间也是 50%。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。

小结

分析完这三个案例,归纳一下平均负载的理解。

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

  • 平均负载高有可能是 CPU 密集型进程导致的;

  • 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;

  • 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。

原文地址:https://www.cnblogs.com/xulan0922/p/13576146.html