程序员在旅途

用这生命中的每一秒,给自己一个不后悔的未来!

0%

Linux系统平均负载(Load Average)处于异常状态的排查思路

一、Linux系统性能分析综述

Linux系统的性能分析优化是一个系统性的工程,需要从宏观和全局的角度来进行,性能分析的目的是为了找出系统瓶颈和优化方案,以提高系统的运行效率和性能。准确的衡量系统的性能表现是进行性能问题分析的前提,一般可以从两个维度来衡量一个Linux系统的性能,从应用负载的视角来考察性能表现,可以使用系统吞吐量和响应延迟来衡量系统提供服务的能力指标,从系统资源的视角层面,可以采用系统资源使用率、饱和度等,例如关注CPU、内存、磁盘IO、网络IO等资源的整体使用情况。
随着应用负载的增加,系统资源的使用也会升高。性能问题的本质在于系统资源已达到瓶颈,即系统资源已经达到了其最大承载能力,但请求的处理仍无法满足需求,无法支持更多的请求。这种情况下,系统就会表现出性能下降的问题,如响应时间变慢、错误增多等。性能分析,其实就是找出应用或系统的瓶颈,并设法去避免或者缓解它们,从而更高效地利用系统资源处理更多的请求,提升系统服务能力。
可以遵循以下思路来进行性能分析:

1.选择合理的指标(应用负载维度、资源使用维度)评估应用程序和系统的性能;
2.明确应用程序和系统性能目标;
3.进行性能基准测试,了解系统提供服务的基准能力;
4.性能分析定位;
5.优化系统和应用程序,完善系统监控和预警。

二、理解系统的平均负载

在Linux系统中,常用平均负载(Load Average)这个性能指标来衡量系统的负载状态,帮助运维人员了解系统的负载状态,从而判断系统是否过载、是否需要优化配置或增加硬件资源等,以保持系统的稳定和高效运行。平均负载是一个关于时间的指标,它衡量了系统活跃的进程数量,指的是单位时间内系统处于可运行状态和不可中断状态的平均进程数,也就是一定时间范围内系统中平均活跃进程数。这些进程包括正在使用CPU运算的进程和等待CPU资源的进程,系统的负载高表明系统同时处理的任务进程比较多。

平均负载示意图

在Linux系统中,通过uptime命令可以看到系统负载情况,通常用三个时间段的平均活跃进程数来描述平均负载情况,通常表示为 1 分钟、5 分钟和 15 分钟的平均负载。这三个值分别代表了过去 1 分钟、5 分钟和 15 分钟内平均活跃的进程数量。
平均负载和另外一个常见的衡量系统状态的指标CPU 使用率并没有直接关系,两者分别用于衡量系统的负载情况和CPU利用率,其中CPU使用率是衡量CPU的工作量的指标,它表示在某个时间段内CPU花费了多少时间来处理计算任务。平均负载并不只是表示CPU的繁忙程度,他是衡量系统整体的负载情况,还包括了其他资源的使用情况,例如磁盘I/O、网络IO等使用情况,当系统中有大量的进程处于等待IO的状态,这时候就会出现系统的负载很高但是CPU使用率却很低的情况,这种现象也恰好说明了两个指标的不同之处。
以上可以了解到:系统负载的升高意味着系统更为繁忙,这种繁忙不仅仅是由于CPU使用率高导致,也可能是由于内存、磁盘、网络等繁忙导致的,理想情况下,平均负载的值应该接近或低于 CPU 核心数。

三、回顾进程

进程存在的主要目的是为了有效地实现并管理多任务和资源分配,作为系统资源管理的基本单位,操作系统使用进程实体可以更好地控制、调度和分配计算机资源。进程管理允许操作系统合理地分配CPU时间片、内存、I/O设备等资源,从而优化系统的性能。
进程是一种动态的实体,是具有生命周期的,操作系统的进程控制能力可以允许进程处于不同的运行状态,主要有:R、S、D、I、Z,这几种状态的表示意义为:

R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。D状态的进程本身是不消耗CPU资源的,因为不是处于R状态,不会被调度执行。
Z 是 Zombie 的缩写,它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。

其中,值得一提的是不可中断的睡眠状态(D),其实是为了保证进程数据与硬件状态一致,并且正常情况下,不可中断状态在很短时间内就会结束。在内核满足不了进程的请求资源情况下,内核就会让进程暂时变成“D”状态。以应用调用了read系统调用读取文件过程为例,read去读取一个文件,这时候进程会从用户态切换到内核态,内核态read()系统调用在读到真正disk上的文件前,会进行一些文件系统层的操作,这些代码指令的消耗属于”sy”,代表内核态CPU使用;接下来,这个read系统调用会向Linux的Block Layer发出一个 I/O Request,触发一个真正的磁盘读取操作,磁盘控制器从磁盘读取读取数据的过程,是不需要CPU的参与的,这时候会让出CPU的控制权处理其他任务,磁盘控制器取数阶段,进程一般会被置为 TASK_UNINTERRUPTIBLE,Linux 会把这段时间标示成”wa”,代表等待I/O的时间,这里的I/O是指 Disk I/O。磁盘控制器取数完毕后会触发硬件中断,内核中断函数开始处理数据,这个时间属于si状态的CPU使用(si状态的CPU不计入进程的CPU使用时间),软中断处理函数做数据的处理后,返回内核态做进一步处理后read系统调用就返回了,进程返回用户态。
处于D状态的进程,由于进程处于系统调用处理的内核态,所以,kill和停止信号都不能被进程接收。此时的进程在sleep等待内核满足它的资源请求之后,再重新变成Runnable状态。资源请求的过程,一般都是对应的设备控制器来处理的(如磁盘控制器查找数据数据),所以,“不可中断”状态进程并不是占着CPU,也不消耗CPU,而是处于睡眠状态且不响应普通结束进程的信号。内核会通过中断来唤醒进程,例如,当等待的磁盘I/O完成,或者等待的锁被释放,使其从D状态转变为可调度执行的R状态。
在 Linux 内核中有数百处调用点会把进程设置为 D 状态,主要集中在 disk I/O 的访问和信号量锁的访问上,因此短时间D状态的进程在 Linux 里是很常见的。无论是对 disk I/O 的访问还是对信号量的访问,都是对 Linux 系统里的资源的一种竞争。当进程处于 D 状态时,就说明进程还没获得资源,这会在应用程序的最终性能上体现出来,也就是用户会发觉应用的性能下降了。

3.1 查看Linux系统中的进程

Linux 通过 /proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,其中/proc/stat 提供了系统资源以及进程相关的状态信息。可以通过查看这个目录下的内容了解到系统的进程情况。更为直接的,是通过ps命令来查看进程信息。
ps 报告了系统中当前进程的一个状态快照,ps 可以选择不同的选项打印出不同展示格式的进程信息。
例如打印出系统中 DR 状态主要可能会导致系统负载升高的进程简要信息:

1
ps -eo pid,stat,%cpu,%mem,command | grep -E '^[DR]' | sort -nr -k3

查看具体某一个进程的资源状态信息也可以使用 pidstat

1
pidstat -du -p <pid>  # d 查看磁盘IO、u查看command -p指定具体的进程

再发现了进程的异常行为后,可以通过strace来跟踪进程执行信息:

1
strace -p <pid>

也可以通过pstree查看父子进程的联系

1
pstree -aps <pid>

3.2 Linux中的几个特殊进程

在Linux系统启动运行的过程中,0、1、2这三个进程起到了至关重要的作用。其中0号进程负责内核级别的初始化和任务,1号进程是用户级别的初始化和进程管理进程,而2号进程是内核线程的管理者,用于执行与内核操作相关的任务。这三个进程共同协作,确保系统正常启动、初始化和运行。

0号进程(内核线程):
作用:0号进程通常表示系统的内核进程,其主要作用是初始化和管理内核线程,以及执行内核级别的任务。这些任务可能包括调度、内存管理、I/O操作和中断处理等。0号进程在初始化 1 号和 2 号进程后,演变为空闲任务。当 CPU 上没有其他任务执行时,就会运行它。
初始化:在引导过程中,0号进程是第一个被内核创建的进程。它负责设置内核数据结构、初始化系统调度器和其他核心组件,以便为其他进程和任务提供运行环境。
不可中断:0号进程是系统中唯一一个不能被终止或杀死的进程,因为它是内核的一部分。
1号进程(init 进程):
作用:1号进程是系统的初始化进程,负责引导系统启动过程、启动其他系统进程和服务,并在系统正常运行期间监控和管理它们。
引导过程:init 进程是系统引导的第一个用户级别进程。它的任务包括执行启动脚本、初始化系统环境和启动系统服务。在一些 Linux 发行版中,init 进程可能被 systemd 或其他进程管理工具替代。
进程管理:init 进程会监控系统中运行的其他进程,以确保它们正常运行,必要时重新启动失败的进程。
2号进程(kthreadd 进程):
作用:2号进程是内核线程管理进程,负责创建、启动和管理内核线程。内核线程是在内核中运行的轻量级进程,通常用于执行与系统操作和硬件交互相关的任务。
内核线程:kthreadd 进程创建内核线程,这些线程用于处理各种内核级别的任务,如磁盘I/O、网络处理、设备驱动程序等。它们是系统中的关键组成部分,确保系统的正常运行。
调度和管理:kthreadd 进程会监控和管理内核线程的运行,确保它们按照需要执行。这些内核线程通常在后台默默地工作,不会与用户级别进程竞争CPU资源。

四、系统负载异常的排查思路

整体思路如下:

先通过top、uptime等命令观察系统的整体负载情况,资源使用情况,然后对比CPU使用率与平均负载的差异,分析引起系统负载高的因素是CPU使用率还是内存、磁盘等IO导致的,是否存在可疑的iowait,如果iowait过高,可以通过iostat排查下系统整体的IO负载情况,搞清楚系统整体的资源使用情况以后,然后就使用pidstat等工具排查具体的引起资源变动的进程,从而找出引起系统负载异常的主导原因。

4.1 分析系统的整体运行情况

4.1.1 查看系统负载是否存在异常

Linux 作为一个多任务操作系统,将每个 CPU 的时间划分为很短的时间片,再通过调度器轮流分配给各个任务使用;
通过top可以从整体上看到系统的负载及CPU、内存等资源的使用情况(top是一个交互式命令,按下1可以可看所有cpu核心的使用情况);

平均负载示意图

top展示了主要两部分的信息:

1.系统统计信息
2.系统进程信息

1.系统统计信息,其中包括:系统负载情况,CPU、内存资源的使用情况
CPU的使用情况,依据处理不同的任务,主要分为:%user、%nice、 %system、%iowait 、%steal等几个方面,分别代表的意思为:

user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
system(通常缩写为 sys),代表内核态 CPU 时间。
idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。

2.系统中运行的进程信息
top也会按照cpu、内存的使用情况列出进程的信息,也可以通过 top -H -p pid 查看一个进程的包含的线程的资源占用情况。
top -H -p 209为例,结果如下:
top-H-p
其中主要的几个字段意义如下:

VIRT 申请的虚拟内存空间;
RES 实际使用的物理内存;
用户态 CPU 使用率 (%usr);
内核态 CPU 使用率(%system);
运行虚拟机 CPU 使用率(%guest);
等待 CPU 使用率(%wait);
总的 CPU 使用率(%CPU)

4.1.2 查看资源使用是否存在异常

1)可以通过 dstat 来查看系统整体的cpu、disk、net的整体使用情况
dstat

2)也可以通过 vmstat 来查看系统整体的cpu、内存、中断等的整体使用情况
vmstat
其中主要的几个字段意义如下:

cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。

对比cpu状态是否在正常的范围内:

1
2
cat /proc/cpuinfo
cat /proc/cpuinfo|grep processor|wc -l

3)分析io读写是否存在瓶颈
可以使用iotop来分析磁盘IO的读写整体状态
4)free、df 查看内存、磁盘状态
df -h 之类查看磁盘使用率,free查看内存使用情况
也可以通过 查看 /proc/meminfo 来分析内存的使用分布情况

4.2 分析不同类型的系统负载状态

4.2.1 cpu利用率高、内存利用率高

使用sort对CPU、内存占用进行排序,找出占用最高的进程,分析其行为

sort #排序命令;
-nr #默认使用字符串排序n代表使用数值进行排序 默认从小到大排序 r代表反向排序;
-k3 #以第3列进行排序。

1
2
ps aux|head -n1;ps aux|grep -v PID|sort -nr -k3|head -n10
ps aux|head -n1;ps aux|grep -v PID|sort -nr -k4|head -n10
4.2.2 io异常,使用率高

分析的整体思路:
1.先使用iostat、iotop、dstat、sar、nfsiostat等工具观察磁盘、文件系统的整体运行情况,判断是否存在IO瓶颈;
2.然后使用pidstat等观察进程的状态,判断是哪个进程导致的IO瓶颈;
3.通过strace、lsof等分析进程的 I/O 行为;结合应用程序的原理,分析这些 I/O 的来源。

1.iostat -d -x 1 5 显示所有磁盘IO的指标

iostat

%util 磁盘 I/O 使用率;
r/s+ w/s ,IOPS,每秒读写次数;
rkB/s+wkB/s ,吞吐量,每秒读写的数据量大小;
r_await+w_await ,响应时间。

sar -p -d 1 5 查看每个磁盘分区的IO读写情况;
nfsiostat,查看挂载的nfs的读写情况;
sar -n NFS 1 5 查看NFS整体的读写情况

2.pidstat -d 查看系统中进程的整体的读写情况,-p 查看具体的某一个进程的情况
pidstat
3.strace -p pid -f 追踪进程及子线程的调用状态
iostat
lsof -p pid 查看进程打开的文件句柄,定位操作的对象。
iostat

五、总结

平均负载是一个重要的衡量系统状态的指标,用于监测系统的运行负载情况。当平均负载持续高于CPU核心数时,意味着系统资源不足或者有某些进程正在消耗大量的资源。这可能导致系统的响应速度变慢或者出现无响应的情况,需要仔细排查并解决性能问题,以确保系统正常运行。