当前位置: 首页 > Linux

本文讲解linux系统负载的介绍

时间:2023-04-06 11:34:41 Linux

:在双十一压测过程中,常见的问题之一就是负载飙升,通常这个时候业务受到影响,比如服务rt飙升,比如机器无法登陆,比如在机器上执行命令挂了等等。这篇文章会讲什么是负载,负载是怎么计算的,什么情况下负载会飙升,负载飙升是否必然影响业务。作者|江冲来源|阿里科技公众号在双十一压测过程中,一个普遍的问题就是负载飙升,一般此时会影响业务,比如服务rt飙升,比如机器无法登陆,比如,在机器上执行命令挂起等等。这篇文章会讲什么是负载,负载是怎么计算的,什么情况下负载会飙升,负载飙升是否必然影响业务。1、什么是负载我们平时说的负载,它的全称是Linuxsystemloadaverages,即linux系统的平均负载。注意两个关键字:一个是“负载”,衡量一个任务(在linux内核中用来描述进程或线程)的系统需求(CPU、内存、IO等),第二个关键字是“Average,计算一段时间内的平均值,有1、5、15分钟的值。系统负载平均值由内核负载计算,记录在/proc/loadavg文件中,由用户态工具(如uptime)读取,top等)。我们一般认为:如果负载接近于0,说明系统处于空闲状态如果1分钟的平均值高于5分钟或15分钟的平均值,说明负载在增加如果1分钟的平均值低于平均5min或者15min,负载在下降如果他们很高由于系统的CPU数量多,系统很可能会遇到性能问题(视情况而定)二、核心算法如何计算简单表达式为:a1=a0factor+a(1-factor),其中a0为上一时刻的值,a1为当前时刻的值,factor为系数,取值范围为[0,1],a是当前某个时刻某个指标的采样值。为什么要用指数移动加权平均法?我个人的理解是1、指数移动加权平均法是指每个值的加权系数随时间呈指数递减。越接近当前时刻,该值的加权系数越大,越能反映近期变化的趋势;2.计算不保存所有过去的值对内核来说非常重要。我们来看看内核是如何计算平均负载的,以下简称负载。上面的指数移动平均公式,a1=a0e+a(1-e),具体到linux负载的计算,a0为前一时刻的负载,a1为当前时刻的负载,e为常数系数,a是当前当前活跃的进程/线程数。上一节提到,Linux内核会计算三个负载值,分别是1分钟/5分钟/15分钟负载。在计算这三个负载值时,使用了三个不同的常数系数e,定义如下:#defineEXP_11884/*1/exp(5sec/1min)*/#defineEXP_52014/*1/exp(5sec/5min)*/#defineEXP_152037/*1/exp(5sec/15min)*/这三个系数怎么来的?公式如下:1884=2048/(power(e,(5/(601))))/e=2.71828*/2014=2048/(power(e,(5/(60*5))))2037=2048/(power(e,(5/(60*15))))其中e=2.71828其实就是自然常数e,也叫欧拉数。那么为什么会有这样的公式呢?其中5表示每5秒采样一次,60表示每分钟采样60秒,1、5、15分别为1分钟、5分钟、15分钟。至于为什么是2048和自然常数e,这涉及到定点计算等一些数学知识,不是我们研究的重点,暂不讨论。让我们看看内核中的实际代码:/**a1=a0*e+a*(1-e)*/staticinlineunsignedlongcalc_load(unsignedlongload,unsignedlongexp,unsignedlongactive){unsignedlongnewload;//FIXED_1=2048newload=load*exp+active*(FIXED_1-exp);if(active>=load)newload+=FIXED_1-1;returnnewload/FIXED_1;}是一个非常直观的实现。上面代码中,第一个参数为前一时刻的负载,第二个参数为常数系数,第三个参数为活跃进程/线程数(包括runnable和uninterruptible)。2计算过程负载的计算分为两步:1.定期更新每个CPU上rq中的活动任务,包括处于可运行状态和不可中断状态的任务,并添加到一个全局变量calc_load_tasks中。2.定期计算负载。负载的计算主要基于上述的calc_load_tasks变量。第一步,每个cpu都要更新calc_load_tasks,但是第二步只有一个cpu来完成,这个cpu叫做tick_do_timer_cpu,它执行do_timer()->calc_global_load()来计算系统负载。整体流程如下图所示。当每个tick到来时(时钟中断),执行如下逻辑:上图中棕色的calc_global_load_tick函数完成第一步,绿色的calc_global_load完成第二步,蓝色的calc_load是前面描述的核心算法部分。这里需要说明的是,calc_global_load是把计算出来的负载值放在一个全局变量avenrun中。其定义为unsignedlongavenrun[3],大小为3,用于存放1/5/15分钟的负载。查看/proc/loadavg时,数据就是从这个avenrun数组中获取的。负载高的三种常见原因从上面负载的计算原理可以看出,负载高的原因很简单,很简单。无非是增加了可运行或不可中断的任务。但也比较复杂,因为导致任务进入不可中断状态的路径有很多(粗略统计,可能有400-500条路径)。个人觉得这种状态有些地方有点被滥用了。根据我多年从事linux内核开发和排错的经验,总结了一些经验供读者参考。1.周期性尖峰一些业务方遇到过周期性的负载尖峰。如果不是因为业务确实存在周期性的峰值,那么大概率是他们在内核计算负载的时候踩到了bug。该bug与内核的负载采样频率(LOAD_FREQ)有关,具体细节不再赘述。ali2016、ali3000、ali4000已修复该bug。如果排除这个原因,可以继续排查是否是磁盘IO的原因。2由于IO引起的磁盘性能瓶颈iostat-dx1可以查看所有磁盘的IO负载情况。当IOPS或BW高时,磁盘成为性能瓶颈,大量线程因为等待IO而处于不间断状态,造成高负载。这时如果用vmstat查看,可能会观察到b列的值猛增,cpuiowait猛增,/proc/stat文件中的procs_blocked值猛增。异常云盘云盘是虚拟磁盘,IO路径长且复杂,容易出现问题。一个常见的异常是IOUTIL100%,avgqu-sz总是不为0,至少为1。不要误会,ioutil100%并不是说磁盘忙,只是表示磁盘中有未完成的IO请求这个设备在每个采样时间的request队列,所以当IO因为某种原因丢失时,云盘上会出现UTIL100%,ECS内核中的jbd2线程和业务线程也会被阻塞,导致负载飙升.JBD2bugJBD2是ext4文件系统的日志系统。一旦jbd2内核线程因为bug挂掉,所有的磁盘IO请求都会被阻塞,大量线程会进入不可中断状态,导致负载飙升。排除IO原因后,再查看内存情况。3、内存原因内存回收任务在申请内存时可能会触发内存回收。如果触发是直接内存回收,会对性能造成很大的损害。当前任务将被阻塞,直到内存回收完成。新的请求可能会增加任务的数量(比如HSF线程池的扩容),负载会飙升。可以通过tsar--cpu--mem--load-i1-l查看,一般会观察到syscpu突然飙升,cache突然下降等现象。内存带宽竞争大家可能只听说过IO带宽、网络带宽,很少关注内存带宽。事实上,内存不仅在容量维度上存在瓶颈,在带宽层面也存在瓶颈,但这个指标是普通工具观察不到的。我们开发的aprof工具可以观察内存带宽竞争情况,在双十一保质期的混合环境下会大显身手。4锁通常是spin_lock在内核的某些路径上会成为瓶颈,尤其是在网络收发包的路径上。可以使用perftop-g查看spin_lock的热点,然后根据函数地址找到内核的源码。伴随的现象可能是sys和softirq飙升。另外,在使用mutex_lock进行并发控制的路径上,一旦某个任务持有锁不释放,其他任务就会处于TASK_UNINTERRUPTIBLE状态等待,也会导致负载飙升。但是如果锁不在关键路径上,可能对业务影响不大。5用户CPU在某些情况下,负载飙升是业务的正常表现。这个时候一般表现为用户CPU在飙升。vmstat看到r列增加,而tsar--load-i1-l看到runq增加。检查proc/pid/schedstats可能会看到第二个数字scheddelay会增加得非常快。四大根源分析1RUNNABLE类型负载飙升分析上面说了,这种情况一般是业务量增加导致的,属于正常现象,但也有可能是业务代码bug导致的,比如长循环甚至死机循环。但是不管是哪一种,一般都可以通过热点分析或者cpu分析来找到原因。oncpu分析的工具有很多,比如perf,比如阿里自己开发的ali-diagnoseperf。2UNINTERRUPTIBLE类型负载飙升分析所谓UNINTERRUPTIBLE就是等待的意思,所以我们只要找出等待的地方,就基本可以找到原因了。查找UNINTERRUPTIBLE状态进程UNINTERRUPTIBLE,通常也称为D状态,以下简称为D状态。有一些简单的工具可以统计当前D态的进程数,稍微复杂一点的工具可以输出D态进程的调用链,也就是栈。此类工具一般从内核提供的proc文件系统中获取数据。查看/proc/${pid}/stat和/proc/${pid}/task/${pid}/stat文件,判断哪些任务处于D状态,如下图:任务。然后检查/proc/${pid}/stack文件以了解任务在何处等待。举个例子:但是有时候,D状态的任务是不固定的,会导致无法捕获D状态或者捕获堆栈不准确。这时候,你就得使出另一个绝招,延迟分析。延迟分析延迟分析需要深入内核,在内核路径上埋点获取数据。所以这类工具的本质就是内核探测,包括systemtap、kprobe、ebpf等。但探针技术必须结合知识和经验才能使其成为实用的工具。阿里开发的ali-diagnose可以进行各种延迟分析,如irq_delay、sys_delay、sched_delay、io_delay、load-monitor。五、总结linux内核是一个复杂的并发系统,各个模块之间的关系错综复杂。但就负载而言,只要从可运行任务和不可中断任务两个维度去分析,总能找到根源。原文链接本文为阿里云原创内容,未经许可不得转载。