找到Linux虚机Load高的"元凶"

问题描述

有客户反馈他们的一台ECS周期性地load升高,他们的业务流量并没有上升,需要我们排查是什么原因造成的,是否因为底层异常?

要弄清Linux虚机load高,我们要搞清楚Linux top命令中Load的含义。

Load average的值从何而来

在使用top命令检查系统负载的时候,可以看到Load averages字段,但是这个字段并不是表示CPU的繁忙程度,而是度量系统整体负载。

Load averages采样是从/proc/loadavg中获取的:

0.00 0.01 0.05 1/161 29703

每个值的含义依次为:

lavg_1 (0.00) 1-分钟平均负载

lavg_5 (0.01) 5-分钟平均负载

lavg_15(0.05) 15-分钟平均负载

nr_running (1) 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思,这个数值是当前可运行的内核调度对象(进程,线程)。

nr_threads (161) 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务),即这个数值表示当前存在系统中的内核可调度对象的数量。

last_pid(29703) 系统最近创建的进程的PID,包括轻量级进程,即线程。

假设当前有两个CPU,则每个CPU的当前任务数为0.00/2=0.00

如果你看到load average数值是10,则表明平均有10个进程在运行或等待状态。有可能系统有很高的负载但是CPU使用率却很低,或者负载很低而CPU利用率很高,因为这两者没有直接关系。

Linux 源码中关于这一块的说明:

Load的计算函数:

从这个函数中可以看到,内核计算load采用的是一种平滑移动的算法,Linux的系统负载指运行队列的平均长度,需要注意的是:可运行的进程是指处于运行队列的进程,不是指正在运行的进程。即进程的状态是TASK_RUNNING或者TASK_UNINTERRUPTIBLE。

Linux内核定义一个长度为3的双字数组avenrun,双字的低11位用于存放负载的小数部分,高21位用于存放整数部分。当进程所耗的 CPU时间片数超过CPU在5秒内能够提供的时间片数时,内核计算上述的三个负载,负载初始化为0。

假设最近1、5、15分钟内的平均负载分别为 load1、load5和load15,那么下一个计算时刻到来时,内核通过下面的算式计算负载:

load1 -= load1 - exp(-5 / 60) -+ n (1 - exp(-5 / 60 ))

load5 -= load5 - exp(-5 / 300) + n (1 - exp(-5 / 300))

load15 = load15 exp(-5 / 900) + n (1 - exp(-5 / 900))

其中,exp(x)为e的x次幂,n为当前运行队列的长度。

如何找出系统中load高时处于运行队列的进程

通过前面的讲解,我们已经明白有可能系统有很高的负载但是CPU使用率却很低,或者负载很低而CPU利用率很高,这两者没有直接关系,如何用脚本统计出来处于运行队列的进程呢?

每隔1s统计一次:

从统计出来的结果可以看到:

注:R代表运行中的队列,D是不可中断的睡眠进程

在load比较高的时候,有大量的nginx处于R或者D状态,他们才是造成load上升的元凶,和我们底层的负载确实是没有关系的。

最后也给大家share一下查CPU使用率比较高的线程小脚本:

如您想学习更多关于软件测试方面的文章,请前往51Testing软件测试网哈~

举报
评论 0