在遇到系统变慢时,我们通常使用top或者uptime命令来了解负载情况,比如输入uptime命令 

root@k8s-master01:~# uptime
06:46:22 up 2 days, 15:37,  3 users,  load average: 0.78, 0.58, 0.62

其中:06:46:22表示当前时间;up 2 days, 15:37表示系统运行时间;3 users表示正在登录的用户数;最后三个数字分别表示过去1min,5min,15min的平均负载。

此命令有两大用处,一个是看机器最近有没有被重启,另一个就是看cpu 负载如何。

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

所谓可运行状态的进程,是指正在使用CPU或者正在等待CPU的进程,也就是使用ps(ps aux中stat列,R表示正在运行或者在队列中的进程,D表示不可中断)命令看到的处于R状态的进程。

理解平均负载_平均负载与CPU使用率的关系

不可中断状态的进程是指正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如ps命令中看到的D状态(等待硬件设备的I/O响应)的进程,如当一个进程向磁盘读写操作时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就是出于不可中断状态,因为如果此时的进程被打断了,就容易出现磁盘与进程数据不一致的问题,因此,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

既然平均负载平均的是活跃进程数,那么理想情况下,就是每个CPU上刚好运行着一个进程,这样每个CPU都能得到充分利用,比如平均负载为2,意味着:

  • 在只有2个CPU的系统上,意味着所有的CPU都刚好完全占用(CPU利用率100%)。
  • 在4个CPU的系统上,意味着CPU的50%未空闲(CPU利用率50%)。
  • 在只有1个CPU的系统上,意味着有一半的进程竞争不到CPU(CPU利用率200%,超载100%)。

一、平均负载多少算合理

平均负载最理想的情况就是等于CPU个数,所以在评判平均负载时,需要知道CPU的个数。这个可以通过top(在top基本视图中,按数字1)或者从/proc/cpuinfo文件中读取。

root@k8s-master01:~# grep 'model name' /proc/cpuinfo | wc -l
4

有了CPU个数,我们就可以判断出,当平均负载比CPU个数大的时候,说明系统已经过载。

uptime命令结果的三个值都是需要看的,三个不同时间间隔的平均值,提供了分析系统负载趋势的数据来源,让我们可以更全面,更立体的理解目前的负载状况。

  • 如果1min,5min,15min的三个值基本相同,或者相差不大,则说明系统平均负载很平稳。
  • 如果1min的值远远小于15min的值,则说明最近1min的负载在减少,过去15min内有很大的负载。
  • 如果1min的值远远大于15min的值,则说明最近1min的负载在增大,这种增大可能是临时的,也可能会持续增加下去,需要持续观察,一旦1min的平均负载接近或者超过CPU个数,就说明系统正在发生过载,就需要分析问题的原因了。

二、平均负载与CPU使用率的关系

平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数,它包括正在使用CPU的进程、等待CPU和等待I/O的进程。

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

  • CPU密集型进程,使用大量CPU会导致平均负载升高,此时两者一致;
  • I/O密集型进程,等待I/O会导致平均负载升高,但是CPU使用率不一定很高;
  • 大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高。

CPU利用率低负载高: 说明等待执行的任务很多(比如I/O等待,大量进程等待等),但是通常任务多CPU使用率也会比较高,如果低就说明CPU根本没工作,那些很多的任务处于等待状态,也可能进程僵死了。

CPU利用率高负载低: 说明任务少,但是任务执行时间长,有可能是程序本身有问题,如果没有问题那么计算完成后则利用率会下降。

生产CPU使用率低而平均负载高的场景: 等待磁盘I/O完成的进程过多,队列长度大,导致负载高,但此时CPU被分配执行别的任务或空闲,具体如:

  • 磁盘读写请求过多导致大量I/O等待: CPU的工作效率要高于磁盘,而进程在CPU上面运行需要访问磁盘文件,这个时候CPU会向内核发起调用文件的请求,让内核去磁盘取文件,这个时候会切换到其他进程或者空闲,这个任务就会转换为不可中断睡眠状态。当这种读写请求过多就会导致不可中断睡眠状态的进程过多,从而导致负载高,CPU低的情况。
  • 数据库抖动: 造成线程队列hang住,负载升高。
  • 外接硬盘故障: 常见有挂了NFS,但是NFS server故障了。比如系统挂载了外接硬盘如NFS共享存储,经常会有大量的读写请求去访问NFS存储的文件,如果这个时候NFS Server故障,那么就会导致进程读写请求一直获取不到资源,从而进程一直是不可中断状态,造成负载很高。

三、平均负载案例分析

接下来,以三个示例来演示这三种情况,并使用iostat,mpstat,pidstat等工具,来找出平均负载升高的根源。

首先准备一台linux机器(4核/8G内存),然后在这台linux机器中安装stress-ng和sysstat包,然后每个场景都需要打开三个终端。

stress是linux系统中的压力测试工具,这里用做异常进程来模拟平均负载升高的场景;sysstat则包含了常用的linux性能工具,用来监控和分析系统的性能,我们这个案例使用到了这个包的mpstat和pidstat。

Ubuntu中安装stress-ng和stress:

apt install -y stress-ng sysstat stress
  • mpstat是一个常用的多核cpu性能分析工具,用来实时查看每个CPU的性能指标,以及所有CPU的平均指标;
  • pidstat是一个常用的进程性能分析工具,用来实时查看进程的CPU,内存,I/O以及上下文切换等性能指标。

3.1 场景一:CPU密集型进程

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

stress --cpu 2 --timeout 600

理解平均负载_mpstat_02

然后,在第二个终端运行uptime查看平均负载的变化情况

# -d参数可以高亮显示变化的区域
watch -d uptime

理解平均负载_pidstat_03

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

mpstat  [-P {|ALL}]  [internal [count]]
参数解释:
#-P: 指定要监控哪个CPU,范围是[0 ~ n-1], ALL表示监控所有CPU都监控
#internal: 相邻两次采样的间隔时间
#count: 采样次数。

mpstat的输出包含了多个列,每列代表不同的 CPU 使用率指标,包括:

  • %usr:用户态使用的 CPU 百分比。
  • %nice:使用 nice 命令对进程进行降级时 CPU 的百分比。
  • %sys:内核进程使用的 CPU 百分比。
  • %iowait:等待进行 I/O 所使用的 CPU 时间百分比。
  • %irq:用于处理系统中断的 CPU 百分比。
  • %soft:用于软件中断的 CPU 百分比。
  • %steal:虚拟机强制 CPU 等待的时间百分比。
  • %guest:虚拟机占用 CPU 时间的百分比。
  • %idle:CPU 的空闲时间的百分比。
# -P ALL表示监控所有CPU,后面的5表示每隔5s输出一组数据
mpstat -P ALL 5

理解平均负载_mpstat_04

从终端二可以看到,1分钟的平均负载会慢慢增加到2以上。从终端三中可以看到,有两个CPU的使用率为100%,但是它的iowait为0,这说明,平均负载的升高是由于部分(核数)CPU的使用率为100%所致。

如果想要查看哪个进程导致CPU使用率为100%,可以使用pidstat查看

pidstat [参数] [时间] [次数]
常用参数说明如下:
-u 默认的参数,显示各个进程的CPU使用统计
-r 显示各个进程的内存使用统计
-d 显示各个进程的IO使用情况
-p 指定进程号
-w 显示每个进程的上下文切换情况
-t 显示选择任务的线程的统计信息外的额外信息
-T { TASK | CHILD | ALL }
这个选项指定了pidstat监控的。TASK表示报告独立的task,CHILD关键字表示报告进程下所有线程统计信息。ALL表示报告独立的task和task下面的所有线程。
注意:task和子线程的全局的统计信息和pidstat选项无关。这些统计信息不会对应到当前的统计间隔,这些统计信息只有在子线程kill或者完成的时候才会被收集。
-V:版本号
-h:在一行上显示了所有活动,这样其他程序可以容易解析。
-I:在SMP环境,表示任务的CPU使用率/内核数量
-l:显示命令名和所有参数

pidstat命令输出字段说明如下:

  •  UID:用户id

 •  PID:进程id

 •  %usr:表示用户进程所使用cpu的百分比

 •  %system:表示内核进程所使用cpu的百分比

 •  %guest:表示运行虚拟处理器时所消耗的cpu时间百分比

 •  %wait:表示任务在等待运行时花费的cpu时间的百分比。

 •  %CPU:表示进程所使用cpu的百分比

 •  CPU:处理进程的cpu编号

 •  Command:进程对应的命令

 注:运行pidstat不加任何选项,统计的信息为系统启动开始的各项统计信息

# 间隔5s输出一组数据
pidstat -u 5 1

理解平均负载_uptime_05

可以看到,stress进程的CPU使用率几乎为100%。

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

首先使用stress命令模拟I/O压力,--hdd表示读写临时文件。

stress-ng主要使用参数

参数

功能

-c N

运行N worker CPU压力测试进程

--cpu-method all

worker从迭代使用30多种不同的压力算法,包括pi, crc16, fft等等

-tastset N

将压力加到指定核心上

-d N

运行N worker HDD write/unlink测试

-i N

运行N worker IO测试

stress-ng -i 1 --hdd 1 --timeout 600

理解平均负载_mpstat_06

然后在第二个终端运行uptime查看平均负载的变化

# -d参数可以高亮显示变化的区域
watch -d uptime

理解平均负载_pidstat_07

接着在第三个终端运行mpstat查看CPU使用率

# 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
mpstat -P ALL 5

理解平均负载_uptime_08

可以看到,1分钟的平均负载升高到5.50,CPU使用率很低,而iowait均很高(mpstat的输出),这说明,平均负载的升高是由于iowait的升高所致。

如果想要查看哪个进程导致CPU使用率飙升,可以使用pidstat查看。可以看到,stress进程的CPU使用率为80%多。

理解平均负载_平均负载与CPU使用率的关系_09

3.3 场景三:大量进程的场景

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

首先我们使用stress命令,模拟16个进程。

stress -c 16 --timeout 600

理解平均负载_uptime_10

由于系统中只有4个CPU,明显比16个进程少的多,因此系统的CPU此时处于严重的过载状态,平均负载高达15.7。

watch -d uptime

理解平均负载_mpstat_11

然后使用pidstat命令来查看进程

理解平均负载_uptime_12

理解平均负载_平均负载与CPU使用率的关系_13

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

四、top命令的说明

通常,top命令通常用于显示系统上的活动进程以及这些进程消耗了多少资源。我们也可以使用这个命令来测量CPU的状态

理解平均负载_平均负载与CPU使用率的关系_14

参数说明:

  • us(user):表示CPU在用户态运行的时间百分比,通常用户态CPU高表示有应用程序比较繁忙。典型的用户态程序包括:数据库、Web服务器等;
  • sy(sys):表示CPU在内核态运行的时间百分比(不包括中断),通常内核态CPU越低越好,否则表示系统存在某些瓶颈
  • ni(nice):表示用nice修正进程优先级的用户态进程执行的CPU时间。nice是一个进程优先级的修正值,如果进程通过它修改了优先级,则会单独统计CPU开销;
  • id(idle):表示CPU处于空闲态的时间占比,此时,CPU会执行一个特定的虚拟进程,名为System Idle Process空闲时间
  • wa(iowait):表示CPU在等待I/O操作完成所花费的时间,通常该指标越低越好,否则表示I/O存在瓶颈,可以用iostat等命令做进一步分析;
  • hi(hardirq):表示CPU处理硬中断所花费的时间。硬中断是由外设硬件(如键盘控制器、硬件传感器等)发出的,需要有中断控制器参与,特点是快速执行;
  • si(softirq):表示CPU处理软中断所花费的时间。软中断是由软件程序(如网络收发、定时调度等)发出的中断信号,特点是延迟执行;
  • st(steal):表示CPU被其他虚拟机占用的时间,仅出现在多虚拟机场景。如果该指标过高,可以检查下宿主机或其他虚拟机是否异常;