在遇到系统变慢时,我们通常使用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状态的进程。
不可中断状态的进程是指正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如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
然后,在第二个终端运行uptime查看平均负载的变化情况
# -d参数可以高亮显示变化的区域
watch -d uptime
最后,在第三个终端运行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
从终端二可以看到,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
可以看到,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
然后在第二个终端运行uptime查看平均负载的变化
# -d参数可以高亮显示变化的区域
watch -d uptime
接着在第三个终端运行mpstat查看CPU使用率
# 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
mpstat -P ALL 5
可以看到,1分钟的平均负载升高到5.50,CPU使用率很低,而iowait均很高(mpstat的输出),这说明,平均负载的升高是由于iowait的升高所致。
如果想要查看哪个进程导致CPU使用率飙升,可以使用pidstat查看。可以看到,stress进程的CPU使用率为80%多。
3.3 场景三:大量进程的场景
当系统中运行的进程超过CPU运行能力时,会出现等待CPU的进程。
首先我们使用stress命令,模拟16个进程。
stress -c 16 --timeout 600
由于系统中只有4个CPU,明显比16个进程少的多,因此系统的CPU此时处于严重的过载状态,平均负载高达15.7。
watch -d uptime
然后使用pidstat命令来查看进程
可以看出,16个进程在争抢4个CPU,单个CPU使用率不到25%,每个进程等待CPU的时间(即%wait列)高达75%多,这些超出了CPU计算能力的进程,最终导致CPU过载。
四、top命令的说明
通常,top
命令通常用于显示系统上的活动进程以及这些进程消耗了多少资源。我们也可以使用这个命令来测量CPU
的状态
参数说明:
- 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被其他虚拟机占用的时间,仅出现在多虚拟机场景。如果该指标过高,可以检查下宿主机或其他虚拟机是否异常;