Linux负载平均:解决神秘

2021-03-11 17:31:56

负载平均值是一个行业关键的公制 - 我的公司基于它们和其他指标花费数百万自动缩放的云实例 - 但是在Linux上有一些幽灵。 Linux加载平均轨道不仅仅是可运行的任务,还可以在不间断睡眠状态下任务。为什么?我从未见过解释。在这篇文章中,我' ll解决了这个神秘,并总结了负载平均值作为每个尝试解释它们的参考。

Linux负载平均值是"系统负载平均值"将系统上的运行线程(任务)的需求显示为平均运行加等待线程的平均数量。这种措施需求,这可以大于系统目前正在处理的需求。大多数工具显示三个平均值,1,5和15分钟:

$正常运行时间16:48:24 up 4:11,1个用户,装载平均:25.25,23.40,23.46top - 16:48:42起4:12,1个用户,载重平均:25.25,23.14,23.37 $ cat / proc / loadavg 25.72 23.19 23.35 42/3411 43603

如果1分钟平均值高于5或15分钟平均值,则负载越来越大。

如果1分钟平均值低于5或15分钟平均值,则负载降低。

如果它们高于CPU计数,那么您可能有性能问题(它取决于)。

作为一组三个,您可以判断负载是否增加或减少,这是有用的。当需要单一的需求时,它们也可以是有用的,例如用于云自动缩放规则。但是在没有其他指标的帮助下,更难以了解他们更加困难。单一值为23 - 25,本身,不均意味着什么,但如果已知CPU计数,并且如果它被称为CPU绑定工作负载,则可能意味着什么。

我通常会切换到其他度量标准,而不是尝试调试加载平均值。我' ll在&#34中讨论这些;更好的指标"截面附近。

原始负载平均仅显示CPU需求:运行加上等待运行的进程数。在RFC 546中标题为" Tenex Load平均值和第34次;,1973年8月:

[1] Tenex负载平均值是CPU需求的衡量标准。负载平均值是给定时间段内可抵押过程的数量的平均值。例如,每小时的负载平均值为10将是(对于单个CPU系统),在那个时刻的任何时间都可以期望看到1个进程运行,9个准备运行的其他(即,没有阻止I / O阻塞)等待对于CPU。

IETF.ORG上的此版本与1973年7月的手绘加载平均图的PDF扫描链接,表明这已被监控数十年:

如今,也可以在线找到旧操作系统的源代码。在这里'除了德克斯(1970年初' s)schedmac:

nrjavs == 3;负载次数我们维护rjav,nrjavs;活动过程数量的指数平均值;更新runnable作业veragesdorjav:movi 2,^ d5000 movem 2,rjatim;下次更新的设置时间4 ,rjtsum; nbproc + ngproc提交4,rjavs1的当前积分;与上次更新Exch 4的差异,rjavs1 fsc 4,233;漂浮它fdvr 4,[5000.0];平均持续5000 ms; exp( - T / C)对于T = 5秒。Expff:Exp 0.920043902; C = 1 min Exp 0.983471344; C = 5 min Exp 0.994459811; C = 15分钟

#define exp_1 1884 / * 1 / Exp(5sec / 1min)作为定点* /#定义EXP_5 2014 / * 1 / EXP(5SEC / 5MIN)* /#定义EXP_15 2037 / * 1 / EXP(5SEC / 15min) * /

旧系统中存在类似的负载平均度量,包括多个数据,其具有指数调度队列平均值。

这三个数字是1,5和15分钟的负载平均值。除了他们aren' t真正的平均值,他们aren' t 1,5和15分钟。如上所述,在上述源中可以看出,1,5和15分钟是在等式中使用的常数,其计算五秒平均值的指数衰减的移动和。由此产生的1,5和15分钟的载荷平均值反射超过1,5和15分钟的负荷。

如果您拍摄了空闲系统,则开始一个线程的CPU绑定工作负载(一个循环中的一个线程),60秒后,一分钟的载荷平均会有多少?如果是平均值,那将是1.0。以下是实验,绘制:

所谓的"一分钟平均值"只有一个分钟标记才达到约0.62。有关更多关于方程和类似的实验,尼尔·冈特尔博士已经写了一篇关于加载平均值的文章:如何运作,加上Loadavg.c中有许多Linux源块注释。

当加载平均在Linux中出现时,它们反映了CPU需求,如其他操作系统。但后来在Linux上改变它们不仅包括可运行的任务,还包括不间断状态的任务(Task_UnintRuptible或NR_UNINTRUPTIBLE)。该状态用于避免信号中断的代码路径使用,该信号包括在磁盘I / O和一些锁上阻止的任务。你可能之前可能看到这个状态:它显示为" D"输出PS和顶部的状态。 PS(1)手册页称它"不间断睡眠(通常是IO)"

添加不间断状态意味着由于磁盘(或NFS)I / O工作负载,Linux负载平均可能会增加,而不仅仅是CPU需求。对于熟悉其他操作系统及其CPU负载平均值的每个人,包括此状态乍一看都很困惑。

负载平均值有无数的文章,其中许多指出了Linux NR_UNINTRUPTIBLE GOTCHA。但是,我看到没有那么解释甚至危害它为什么猜测它'包括为什么。我自己的猜测是它的意思是反映更一般意义的需求,而不是CPU需求。

了解为什么Linux中改变的事情很容易:您在问题上读取了在文件中的Git提交历史记录,并阅读了更改说明。我检查了loadavg.c上的历史记录,但添加了不间断状态的更改会在较早文件中使用代码创建的文件。我检查了另一个文件,但这也是冷的:代码本身跳过不同的文件。希望拍摄快捷方式,我倾倒" git log -p"对于整个Linux Github存储库,这是4 GB的文本,并开始向后读取它,看看代码何时出现。这也是一个死胡同。当Linus导入Linux 2.6.12-RC2时,整个Linux Repo的最旧的更改返回到2005年,此更改会达到。

有历史Linux Repos(这里和此处),但也缺少此更改描述。至少试图发现这种变化发生时,我在kernel.org上搜索了tarballs,发现它已经改变了0.99.15,而不是0.99.13 - 但是,0.99.14的Tarball缺失。我在其他地方找到了它,并确认了改变在Linux 0.99 PatchLevel 1993年11月14日。我希望Linus的0.99.14释放描述将解释变化,但也是一个死胡同:

"上次官方发布的变更(p13)太多了,以提及(甚至要记住)..." - Linus.

基于日期,我查询内核邮件列表档案,以查找实际补丁,但最古老的电子邮件是从1995年6月开始的,当时Sysadmin写道:

"在一个系统上工作,使这些邮寄档案规模MoreeffecityIvely我意外地摧毁了当前的档案(Ahwhoops)。"

我的搜索开始被诅咒。值得庆幸的是,我发现了一些旧的Linux-devel邮件列表存档,从服务器备份中救出,通常存储为摘要的tarball。我搜索了超过6,000多家摘要,其中包含超过98,000封电子邮件,其中30,000人来自1993年。但是,在某些人中失踪了。它真的看起来好像原始补丁描述可能永远丢失,而#34;为什么"仍然是一个谜。

幸运的是,我终于在1993年在Oldlinux.org中找到了一个压缩的邮箱文件中的更改。这里是:

来自:Matthias Urlichs< [email protected]& gt;主题:负载平均破碎?日期:星期五,1993年10月1993年10月11:37:23 +0200只有核心" runnable"计算加载均值时的过程。我不喜欢那样;问题是在&#34上交换或#34的进程;快速"即不间断,I / O,也消耗资源。当您使用缓慢的交换磁盘时,负载平均值下降似乎有些不合适磁盘......无论如何,以下补丁似乎使负载平均更加孤立的WRT系统的主观速度。而且,最重要的是,当没有人在做任何事情时,更为重要的是零。 ; - )--- kernel / sched.c.orig fri fri 29 10:31:11 1993 +++ kernel / sched.c fri fri 2019年10月10:32:51 1993 @@ -414,7 +414,9 @ @ unsigned long nr = 0; for(p =& last_task; p>& first_task; - p) - if(* p&&(* p) - >状态== task_running)+如果(* p&&( (* p) - > state == task_running)|| +(* p) - > state == task_uninteruptible)|| +(* p) - > state == task_swappe))nr + = fixed_1;返回nr; } - Matthias Urlichs \ XLink-Pop n | rnberg |电子邮件:[email protected]_e 12 \ Unix + Linux + Mac |电话:...请使用电子邮件.90491 n | rnberg(德国)\咨询+网络+编程+等等' ing 42

这证实了负载平均值被故意改变以反映对其他系统资源的需求,而不仅仅是CPU。 Linux从&#34改变; CPU负载平均值"到一个人可能会呼叫"系统负载平均值"

他使用较慢的交换磁盘的示例是有意义的:通过降级系统和#39; S的性能,对系统的需求(测量为+排队)应该增加。但是,负载平均值减少,因为它们仅跟踪CPU运行状态而不是交换状态。 Matthias认为这是不必要的,所以他修好了它。

但是Don' T Linux负载平均值有时会过高,超过磁盘I / O解释的更多?虽然我的猜测是,这是由于使用Task_uninteruptible的新代码路径,它在1993年中存在。在Linux 0.99.14中,有13个CodePath直接设置Task_uninteruptible或Task_swapping(稍后删除交换状态)来自Linux)。如今,在Linux 4.12中,有近400个代码夫人设置了Task_UnintRuptibly,包括一些锁定基元。它可能包含其中一个CodePaths不应包含在负载平均值中。下次我有加载平均值,似乎太高,i' ll请参阅是否是这种情况,如果它可以修复。

我通过电子邮件发送了Matthias(第一次),询问他几乎他近24年后的负载平均变化的想法。他在一小时内回复(正如我在Twitter上提到的),并写道:

""加载平均值"是到达有关系统来自人类角度的繁忙的数字。 Task_Un中断性意味着(含义?)该过程正在等待像磁盘读取的内容有助于系统加载。一个庞大的磁盘束缚系统可能是不贬低的,但只有0.1的Task_running平均值,其中NOTOONNN和#39; T帮助任何人。"

(如此迅速地获得回复,甚至一切都是回应,真的让我的一天。谢谢!)

所以Matthias仍然认为它是有道理的,至少给出了什么Task_uninterruptible常用。

但是Task_Unitible今天匹配更多的东西。我们应该改变负载平均值只是CPU和磁盘需求吗? Scheduler维护者Peter Zijstra已经向我发送了一个聪明的选项来探索这样做:包括task_struct-> in_iowait在加载平均值而不是task_uninteruptible,因此它更紧密地匹配磁盘I / O.然而,它乞求另一个问题,这是我们真正想要的?我们是否希望在线程方面测量系统的需求,或仅对物理资源的需求?如果它是前者'那么等待不间断锁的等待应该包括在系统上的那些线程。他们不闲着。所以也许Linux负载平均已经正常工作。

更好地了解不间断的代码路径,我' d喜欢在行动中测量它们的方法。然后我们可以检查不同的例子,量化在其中所花费的时间,并查看它是否都是有意义的。

以下是从生产服务器,跨越60秒并仅显示内核堆栈的关注点火焰图,其中i' m过滤仅包括任务_un中间状态(svg)中的内核堆栈。它提供了许多不间断代码路径的示例:

如果您是off-CPU火焰图的新增功能:您可以单击框架以放大,检查显示为帧塔的完整堆栈。 x轴大小与堵塞关CPU的时间成比例,并且排序顺序(左到右)没有真正的含义。用于关注CPU堆栈的颜色为蓝色(我使用On-CPU堆栈的暖色),饱和度具有随机方差来区分帧。

我使用来自BCC的我的offcputime工具生成了这一点(此工具需要来自Linux 4.8+的EBPF功能),以及我的Flame图软件:

#./bcc/tools/offcputime.py -k --state 2 -f 60> out.stacks#awk' {打印$ 1,$ 2/1000}' out.stacks | ./flamegraph/flamegraph.pl --color = io --countname = ms> out.offcpu.svgb>

使用awk将输出从微秒更改为milliSeconds的i' offcputime" - 州2"匹配Task_unintRuptible(请参阅sched.h),是我刚刚为此帖子添加的选项。 Facebook' S Josef Bacik首先用他的Kernelscope工具做到了这个,这也使用了BCC和火焰图。在我的例子中,i' m只是显示内核堆栈,但offcputime.py支持显示用户堆栈。

至于上面的火焰图:它表明,在不间断的睡眠中仅花了60秒的926毫秒。 '只添加0.015到我们的负载平均值。它'在一些cgroup路径中的时间,但这台服务器没有做太多磁盘I / O.

右侧的宽塔在proc_pid_cmdline_read()中显示systemd-journal_read()(读取/ proc / pid / cmdline),被阻止,并为负载平均贡献0.07。左侧有一个更广泛的页面错误塔,即在RWSEM_DOWN_READ_FAILED()中也已最终(增加0.23到负载平均值)。我突出了洋红色中的那些函数使用火焰图搜索功能。这里' rwsem_down_read_failed()的摘录:

/ *等待锁定* / while(true){set_task_state(tsk,task_unintruptible);如果(!waiteer.task)休息;日程(); }

这是锁采集代码,' s使用task_uninteruptible。 Linux具有不间断和可中断版本的互斥锁获取功能(例如,mutex_lock()vs mutex_lock_interruptible(),down()和down_interruptible()用于信号量)。中断版本允许任务由信号中断,然后在获取锁之前唤醒以处理它。不间断锁定的时间通常不会增加负载平均值,但在这种情况下,他们正在增加0.30。如果这要高得多,值得分析,看看是否可以减少锁争用(例如,i' d在systemd-journal和proc_pid_cmdline_read()!)上开始挖掘,这应该提高性能并降低负载平均值。

这些代码路径是否包含在负载平均值中是有意义的吗?是的,我' d这么说。那些线程在进行工作的中间,并发生在锁上。他们不闲着。它们是对系统的需求,尽管用于软件资源而不是硬件资源。

Linux加载平均值是否可以完全分解成组件?这里的一个例子:在空闲8个CPU系统上,我推出了归档了一些未加工的文件。它花费了几分钟大部分磁盘读取。以下是从三个不同的终端窗口收集的统计数据:

terma $ pidstat -p`pgrep-x tar` 60linux 4.9.0-rc5-virtual(bgregg-xenial-bpf-i-0b7296777a2585be1)08/01/2017_x86_64_(8 CPU)10:15:51 PM UID PID%USR %System%Guest%CPU CPU Command10:16:51 PM 0 18468 2.85 29.77 0.85 29.77 0.00 32.62 3 tartermb $ iostat-x 60 [...] avg-cpu:%用户%nice%system%iowait%窃听%空闲0.54 0.03 8.24 0.09 87.10DEVICE:RRQM / S WRQM / SR / SW / S RKB / S WKB / S AVGRQ-SZ-SZ-SZ AVGQU-SZ AWAIT R_AWAIT W_AWAIT SVCTM%utilXVDAP1 0.05 0.05 30.83 0.18 638.33 0.93 41.22 0.0.06 1.84 1.83 3.64 0.06 1.21xvdb 958.18 1333.83 2045.30 499.38 60965.27 63721.67 98.00 3.97 1.56 0.31 6.67 0.24 60.47xvdc 957.63 1333.78 2054.55 499.38 61018.87 63722.13 97.69 4.21 1.65 0.33 7.08 0.24 0.00 61.65md0 0.00 4383.73 1991.63 121984.13 127443.80 78.25 0.00 0.00 0.00 0.00 0.00 0.00termc $运行时间22时15分五十零秒了154天, 23:20,5个用户,加载平均:1.25,1.19,1.05 [...] Termc $正常运行时间22:17:14增长154天,23:21,5用户,装载平均:1.19,1.17,1.06

0.67来自焦油' S不间断磁盘读取,推断(offcpu火焰图在0.69时,我怀疑它开始稍后收集并跨越略微不同的时间范围)

0.04来自其他CPU消费者(iostat用户+系统,减去PIDStat的CPU)

0.11来自内核工作者不间断磁盘I / O时间,刷新磁盘写入(offcpu火焰图,左侧的两个塔)

增加到1.15。 i' m仍然缺少0.04,其中一些可能是舍入和测量间隔偏移误差,但很多可能是由于负载平均值是指数衰减的移动和,而另一个平均值i' m使用( PIDSTAT,IOSTAT)是正常平均值。在1.19之前,一分钟平均为1.25,因此其中一些仍将拖延我们。多少?从我之前的图表中,在一个分钟的标记,62%的公制来自那一分钟,其余的年龄较大。所以0.62 x 1.15 + 0.38 x 1.25 = 1.18。那个'非常接近1.19报道。

这是一个线程(焦油)加一倍(在内核工作线程中的一段时间)正在进行工作的系统,Linux将负载平均报告为1.19,这是有意义的。如果它是测量" CPU负载平均值",系统将报告0.37(从MPSTAT' s摘要推断出来,这对于CPU资源来说是正确的,但隐藏了有需要的事实一个螺纹'值得的工作。

我希望这个例子表明,数字确实意味着刻意的东西(CPU +不间断),你可以分解它们并弄清楚。

我与iSS一起长大,其中加载平均值意味着CPU负载平均值,因此Linux版本一直困扰我。也许这一切都是真正的问题是单词"负载平均值"关于" I / O"哪种类型的I / O?磁盘I / O?文件系统I / O?网络I / O? ......同样,加载平均值? CPU负载平均值?系统加载平均值?以这种方式澄清它让我喜欢这样的意识:

在Linux上,负载平均值是(或尝试是)"系统加载平均值"为系统整体,测量工作和等待工作的线程数(CPU,磁盘,不间断锁定)。换句话说,它测量areN的线程数量且完全闲置。优势:包括对不同资源的需求。

在其他操作系统上,负载平均值是" CPU负载平均值&#34 ;,测量运行的CPU + CPU RUNNABLE线程的数量。优点:可以更容易理解和理由(仅限CPU)。

请注意,另一种可能类型:"物理资源负载平均值",其中仅包括物理资源(CPU +磁盘)的负载。

也许有一天我们' ll为Linux添加额外的负载平均值,让用户选择他们想要使用的内容:单独的" CPU负载平均值""磁盘负荷平均值", "网络负载平均值"等等或只是使用不同的指标。

有些人发现似乎为他们的系统和工作负载工作的价值观:他们知道当加载到x时,应用程序延迟很高,客户开始抱怨。但是,没有真正的规定这个问题。

使用CPU负载平均值,可以通过CPU计数划分值,然后说如果该比率超过1.0,则在饱和度下运行,这可能会导致性能

......