更加深入的分析load average

昨天在研究load average的时候谈到了LINUX系统与其他UNIX系统的不同。为什么会有一些不同呢?可能很多朋友觉得也没必要太较真了,今天下班前正好有点空,我就这个问题继续在谷歌上做一些搜索,并在reddit上看了一些LINUX开发者的讨论。通过这些研究,似乎对load average的理解更为深刻了一些。

更加深入的分析load average

首先我们先来看看linux代码中loadavg.c的注释部分,看整个代码太累,不过看注释基本上也就能够理解这个算法。和我昨天说的是差不多的。首先根据每个CPU核去统计nr_running+nr_uniterruptible的值,作为nr_active。后面一个公式是衰减公式。在老白二十多年前学习UNIX的时候,平均负载的概念等同于平均CPU负载,因为除了LINUX外,其他的UNIX的负载基本上都是基于CPU负载来计算的。而目前LINUX上的平均负载的概念是“平均系统负载”,LINUX中的系统负载不完全等同于CPU负载。load average这个指标起源于1973年的RFC 546:

更加深入的分析load average

最初的目标是为网络设备的CPU负荷制定一个统一的度量指标。其指标的值就是正在运行的进程数+等待运行的进程数。后来这个指标被UNIX系统引入了,含义还是相同的。这个指标在LINUX上发生了很大变化的起因是因为1993年的一个LINUX开发者遇到的一个问题。当时一个客户提出他的系统CPU很空闲,但是大量的线程在等待IO,而这个等待会十分短暂,很快这些进程就需要大量使用CPU去处理IO了。如果这样的系统也被认为是低负载的系统,是不合理的,于是这个程序员把等待IO的线程也记录在负载中了。下面的这个邮件记录了这段历史。

从上面的代码可以看出,当时计算Load是三种类型的,其中TASK_SWAPPING是记录正在换页的状态,这个状态在后来的LINUX版本中被去除了,只剩下了TASK_UNINTERRUPTIBLE,后来被改为nr_uniterruptible)。当时nr_uninterruptible状态的线程只有一种等待事件,就是IO,从此以后,LINUX的LOAD AVERAGE可以反映出CPU使用和IO负载两种负载情况,而不仅仅是CPU的负载,这是十分重要的,因为大多RDBMS系统表现出来的就是这样一种负载状况。如果用网络设备使用的load average定义来评估RDBMS应用的场景,产生的偏差是十分巨大的。随着数据库等重负载应用的高速发展,评价服务器负载不能仅仅看纯CPU的消耗,也要关注正在短暂等待IO,马上就会大量消耗CPU的线程,LINUX上对于LOAD average的这种重新定义是符合信息技术的发展潮流的。

不过让这位偶然修改了几行代码的程序员始料未及的是,随着计算机软硬件的发展,LINUX发展的太快了。随着LINUX的发展,TASK_UNINTERRUPTIBLE也就是nr_uninterruptible状态不仅仅是在等待IO,到了LINUX 1.x的时候,就有十几条等待路径会被标识为nr_uninterruptible。而到了最新的4.x内核,有400多条路径可以让线程处于nr_uninterruptible状态,线程等待系统锁资源也可能会处于nr_uninterruptible状态。

虽然LINUX内核发生了巨变,但是loadavg.c的核心算法并没有发生变化,所以说目前的loadavg已经发生了很大的变化。因为nr_uninterruptible状态的情况变得复杂,因此loadavg作为单一的体现系统负载的指标,可能有些时候无法真正体现出系统负载了。比如我们昨天提到的一种情况,NFS文件系统出现了问题,访问这个文件系统的所有的线程都会被标识为nr_uninterruptible状态,并且长久的挂死在系统中。这时候实际上系统的负载是十分低的,但是我们还是可能看到十分高的load average。这种情况下load average就出现了严重的偏差。

如果单一的使用loadavg来进行负载的分析会存在一定的偏差。不幸的是,现在好多负载均衡的策略都是基于loadavg的,比如oracle rac的Load balance就是根据不同实例的loadavg来确定新连接会话的位置的,K8S和云平台也会根据loadavg来调度POD和vm,其目的也是为了通过CPU与IO负载作为调度资源的最重要的依据。

如果loadavg有时候会出现不准确的情况,会如何影响这些使用loadavg作为资源调度基准的应用呢?实际上以前我们在Oracle RAC上就经常能看到多个RAC节点中,实际上CPU使用率都差不多,但是连接的会话数总是会出现极为不均匀的情况,这样就会导致业务高峰期,多个RAC节点之间的资源出现严重的不均衡。这种情况有很大一部分原因就出现在loadavg计算出现偏差的时候。

看样子loadavg有时候会不靠谱,但是我们还不得不使用它。既然了解了loadavg的原理,那么我们该如何更好的使用它呢?在运维自动化系统中,我们不能够单一的使用这个指标来判断系统的负载。如果我们需要分析CPU负载,我们可以单一的通过runable队列的深度来进行判断,再结合CPU的使用率来定位负载。对于IO,我们可以通过b队列的深度和WIO的比例来判断IO的负载。

如果我们发现了loadavg比较高,CPU使用率也比较高,r队列也比较大,那么我们就一定能够确定CPU已经出现了瓶颈,并已经影响了系统的性能吗?答案是不一定。因为哪怕r大于CPU的核数,也不一定说明CPU资源就一定影响了性能。不同的应用特点与不同性能指标的CPU下,这些都是变数。如果我们真的需要判断CPU调度是否已经成为了瓶颈(其实目前大多数情况下我们不需要这么做),那么/proc/schedstat,/proc/sched_debug等统计数据数据可以成为精准分析的重要依据。比如下面的awk命令就是分析sched_debug文件,取出等待时间最长的20个进程调度。从等待时间的长短就可以更为精细的分析CPU资源调度是否存在了瓶颈。在缺省情况下,kernel.sched_schedstats参数是0,我们是无法跟踪CPU调度等待的,如果要做下面的分析首先要设置该参数为1:

一定要记得分析完,要把这个参数恢复为0,否则会产生较大的系统开销。

awk ‘NF > 7 { if ($1 == “task”) { if (h == 0) { print; h=1 } } else { print } }’ /proc/sched_debug |sort -rnk 6|head -n 20如果我们没有开启调度的DEBUG或者系统的CPU负载较低的时候,看到的wait-time应该都是0,或者是比较低的值。

第六列就是wait-time,在一个空闲的系统中,所有的调度等待都是0。我们给系统用linpack加点压力后再来看这个数据。

这时候r队列已经很高了,再看看结果:

可以明显的看到,wait-time已经很高了。这时候CPU已经出现了十分严重的瓶颈。

通过上面的方式进行分析,根据wait_time就可以了解CPU调度的等待时间,如果等待时间变长,那么CPU瓶颈可能真的成为影响系统性能的主要因素了,否则你就放宽心吧。

似乎今天老白讲的东西对于一个运维人员来说,已经太复杂了。绝大多数内容可能是屠龙技,平时都用不到。不过知识这东西,能够多了解一些总是好的,保不齐啥时候还真的就用到了呢。


更加深入的分析load average》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/2192.html