如何理解 Linux 中的 load averages

原文:https://mp.weixin.qq.com/s?src=11&timestamp=1533697106&ver=1047&signature=poqrJFfcNABv4biKKpa4mZdIW7No2Wo1F5sbZL7ggoVS2GqcSqwQQ8hMulAmezT*zL*klB-eE5BeMyNuyjuIH7YgkBAN25i6*ahhEpWyxqx6vPct-Vr7q7AU0YGe-F*l&new=1

http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages

经常和 Linux 打交道的童鞋都知道,load averages 是衡量机器负载的关键指标,但是这个指标是怎样定义出来的呢?
和其他系统不同,Linux 上的 load averages 不仅追踪可运行的任务,还追踪处于不可中断睡眠状态的任务,为什么是这样呢?这篇文章就来聊聊这方面的知识。
Linux 的 load averages 是系统负载平均值,这个值将正在运行线程(任务)对于系统的需求,作为处于运行和等待状态的线程的平均数量。大多数工具会显示 1 分钟,5 分钟和 15 分钟的平均值:

$ uptime17:30:01 up 13 days, 20:30,  3 users,  load average: 1.66, 2.03, 2.08$ cat /proc/loadavg
1.48 1.98 2.06 4/3587 117385

对上面的输出信息稍稍做些解释

  • 如果平均值是 0.0,说明系统处于空闲状态
  • 如果 1 分钟的平均值大于 5 分钟或者 15 分钟,说明系统负载正在增加
  • 如果 1 分钟的平均值小于 5 分钟或者 15 分钟,说明系统负载正在减小
  • 如果这些值大于 CPU 的核数,说明可能遇到了性能问题

利用这三个值,我们可以判断系统的负载是在增加还是在减小,这在实践中很有用。这三个中的任意一个拿出来也很有用,比如为云服务的自动伸缩设置阈值。不过,在缺少其他信息的情况下,单看这些值是没有意义的。比如 1 分钟的 load averages 值在 23 到 25 之间,就没有任何意义;但如果知道 CPU 核数并且知道运行的任务是计算密集型,那这个值就很有意义。

历史

最开始的时候,load averages 只显示对系统 CPU 相关的需求:运行的进程数加上等待的进程数。如 RFC 546 描述的:

TENEX load averages 是衡量 CPU 需求的指标。这个值是给定时间内可运行进程数量的平均值。例如,对于单核 CPU 系统,每小时平均 10 次意思是在该小时内可以期望看到一个进程正在运行和另外九个等待 CPU(即没有被 I/O 阻塞) 处于 ready 状态的进程。

下图是 1973 年绘制的监控图:

image

以前操作系统的代码还可以找到,下面是 TENEX) 定义的一些宏:

NRJAVS==3               ;NUMBER OF LOAD AVERAGES WE MAINTAIN
GS RJAV,NRJAVS          ;EXPONENTIAL AVERAGES OF NUMBER OF ACTIVE PROCESSES
[...]
;UPDATE RUNNABLE JOB AVERAGESDORJAV: MOVEI 2,^D5000MOVEM 2,RJATIM          ;SET TIME OF NEXT UPDATEMOVE 4,RJTSUM           ;CURRENT INTEGRAL OF NBPROC+NGPROCSUBM 4,RJAVS1           ;DIFFERENCE FROM LAST UPDATEEXCH 4,RJAVS1FSC 4,233               ;FLOAT ITFDVR 4,[5000.0]         ;AVERAGE OVER LAST 5000 MS
[...]
;TABLE OF EXP(-T/C) FOR T = 5 SEC.EXPFF:  EXP 0.920043902 ;C = 1 MINEXP 0.983471344 ;C = 5 MINEXP 0.994459811 ;C = 15 MIN

Linux 中定义的宏长下面这样(代码出处 include/linux/sched/loadavg.h):

#define EXP_1           1884            /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5           2014            /* 1/exp(5sec/5min) */
#define EXP_15          2037            /* 1/exp(5sec/15min) */

指标的三个粒度

load averages 有 1 分钟,5 分钟,15 分钟三个粒度的结果。不过事实上,他们并不是真正的平均值,统计的粒度也不是 1,5,15 分钟。从上面的代码中可以看出,1,5 和 15 都是常量,用于计算指数衰减的 5 秒平均移动和。由此算出的 1 分钟,5 分钟和 15 分钟的 load averages 所反应的负载远远超过 1,5,15 分钟。

假设在一个空闲的系统上,开启一个单线程来跑 CPU 密集任务,60 秒后 1 分钟的 load averages 是多少呢?如果 load averages 按普通平均值来算,这个值将是 1.0. 下面是一个绘制成图的实验结果:

image

在上面的实验中,所谓的“1 分钟 load averages”在一分钟内只能达到 0.62 左右。

Linux 不可中断任务

Linux 中刚引入 load averages 时,和其他系统一样将其作为衡量 CPU 需求的指标,后来将其更改为不仅包含可运行任务,还包含处于不可中断状态的任务(TASK_UNINTERRUPTIBLE 或 nr_uninterruptible)。这种状态由希望避免信号中断的代码使用,其中包括阻塞在磁盘 I/O 和一些锁上的任务。在pstop的输出中,这种状态被标志为“D”。ps(1) 的 man page 将其称为"不可中断睡眠状态(通常被 IO 阻塞)"

# man ps
.....
PROCESS STATE CODESHere are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to describe thestate of a process:D    uninterruptible sleep (usually IO)...

为什么 Linux 中的 load averages 要加入不可中断状态呢,而不是像其他系统一样只计算 CPU 的需求呢?

加入不可中断的起源

在 oldlinux.org 找到了一封 1993 年的邮件:

From: Matthias Urlichs <urlichs@smurf.sub.org>
Subject: Load average broken ?
Date: Fri, 29 Oct 1993 11:37:23 +0200The kernel only counts "runnable" processes when computing the load average.
I don't like that; the problem is that processes which are swapping or
waiting on "fast", i.e. noninterruptible, I/O, also consume resources.It seems somewhat nonintuitive that the load average goes down when you
replace your fast swap disk with a slow swap disk...Anyway, the following patch seems to make the load average much more
consistent WRT the subjective speed of the system. And, most important, the
load is still zero when nobody is doing anything. ;-)--- kernel/sched.c.orig Fri Oct 29 10:31:11 1993
+++ kernel/sched.c  Fri Oct 29 10:32:51 1993
@@ -414,7 +414,9 @@unsigned long nr = 0;for(p = &LAST_TASK; p > &FIRST_TASK; --p)
-       if (*p && (*p)->state == TASK_RUNNING)
+       if (*p && ((*p)->state == TASK_RUNNING) ||
+                  (*p)->state == TASK_UNINTERRUPTIBLE) ||
+                  (*p)->state == TASK_SWAPPING))nr += FIXED_1;return nr;}
--
Matthias Urlichs        \ XLink-POP N|rnberg   | EMail: urlichs@smurf.sub.org
Schleiermacherstra_e 12  \  Unix+Linux+Mac     | Phone: ...please use email.
90491 N|rnberg (Germany)  \   Consulting+Networking+Programming+etc'ing      42

看到这么久之前的想法还是很令人惊叹的。

这也证明了 Linux 改变 load averages 的含义,使其不仅体现对 CPU 的需要,是有意的,这让 load averages 从“CPU 负载均衡”变成了“系统负载均衡”。

邮件中举交换磁盘速度慢的例子是有道理的:通过降低系统性能,系统需求(运行和排队的进程数)应该增加;但是如果仅仅根据 CPU 运行状态,那么 load averages 值应该会下降。Matthias 认为这是不直观的,所以修改了代码。

现代系统的不可中断

但是难道不会出现磁盘 I/O 不能解释 Linux load averages 过高的情况吗?这种情况是会出现的,这是因为在现代 Linux(4.12)版本中,有将近 400 处代码设置了TASK_UNINTERRUPTIBLE状态,包括一些锁原语中。其中部分代码可能不需要统计在 load averages 中。

既然TASK_UNINTERRUPTIBLE在更多的地方被用到,那么是否应该将 load averages 改成只统计 CPU 和磁盘需求呢?Linux 调度程序的维护者 Peter Zijstra 有一个想法:将TASK_UNINTERRUPTIBLE替换成task_struct->in_iowait,这样 load averages 就更贴近磁盘 I/O 的需求。这样又引入了另外一个问题,我们到底想要从 load averages 中得到什么?我们是需要用线程对系统的需求来衡量负载,还是只通过物理资源的使用情况来衡量负载呢?如果是前者的话,那么应该包含等待不间断锁的线程,因为这些线程并没有闲置。所以也许 Linux 的 load averages 已经按我们需要的方式工作了。

理解 Linux 的 load averages

也许真正的问题在于“load averages”这个词和“I/O”一样含糊不清。到底是哪种 I/O 呢?是磁盘 I/O?文件系统 I/O?还是网络 I/O。类似的,到底是哪种 load averages 呢?是 CPU 平均负载?还是系统平均负载?下面做一个总结吧:

  • 在 Linux 上,load averages 的真实含义是“系统平均负载”,即对整个系统,测量正在工作并等待工作的线程数(CPU,磁盘,不可中断锁)。换句话说,这种方式测量的是不完全空闲的线程数量。这种方式的优势在于包括了对不同资源的需求。
  • 在其他的系统上,load averages 的含义是“CPU 平均负载”,这组值用于测量正在占有 CPU 执行权的线程数量加上等待 CPU 的线程数量。

还有另一种可能的类型:“物理资源负载平均值”,其中包括仅用于物理资源(CPU+ 磁盘)的负载。

更精确的测量数据

当 Linux 的 load averages 值增加时,可以判断任务对系统资源(CPU,磁盘和锁)有了更高的需求,但是到底是对哪种资源的需求增长了呢?这时可以用其他的指标来进行判断。比如,CPU 资源有如下指标:

  • 单个 CPU 使用率:可以用命令mpstat -P ALL 1查看
  • 每个进程的 CPU 使用率:可用命令toppidstat 1查看
  • 每个线程运行队列(调度程序)延迟:可用命令perf sched查看,也可以查看文件/proc/PID/schedstats
  • CPU 运行队列延迟:可用命令perf sched查看,也可以查看文件/proc/schedstat
  • CPU 运行队列长度:可用vmstat 1命令查看。

上面提供的指标中,前两个用来衡量使用率,后三个用来度量系统饱和度。利用率指标对于衡量工作负载很有用,而饱和度指标可用来识别性能问题。衡量 CPU 饱和度的最佳指标是运行队列(或调度程序)的延迟,延迟是指任务或者线程处于可运行状态,但必须等待 CPU 的时间。通过这样的指标可以用来衡量性能问题的严重程度,比如线程等待调度的时间在运行时间中占的百分比。通过观察运行队列长度可以很方便判断是否存在问题,但比较难定位到问题产生的原因。

schedstats功能在 Linux 4.6 中成为内核可调参数(sysctl.kernel.sched_schedstats),默认是关闭的。

尽管有更明确的指标,但并不意味着 load averages 是无用的。这组指标已经成功用于云计算微服务的扩展策略,微服务根据不同的负载值做出反应。有了这些判断的依据,即使在自动扩容时犯错也保险多了:扩容实例会花更多的钱,不扩容则会损失用户。如果扩容太多,后来调查一下纠正就是了。

总结

在 1993 年,一位 Linux 工程师发现了一个非直观的 load averages 情况,于是提交了三行代码的补丁将 load averages 的含义由“CPU 负载平均值”变成了“系统负载平均值”。这次的变动在统计中包括了不可中断状态下的任务,所以 load averages 值不仅反映了对 CPU 的需求,还反映了对磁盘资源的需求。系统平均负载计算正在工作和等待工作的线程的数量,并且统计 1 分钟,5 分钟,15 分钟指数衰减的移动总和平均值。通过这三个值,能够知道系统的负载是在增加还是在减小。

Linux 中对不可中断状态的使用越来越多,现在已经包括了不可中断的锁原语。如果需要衡量处于运行状态和等待状态的线程对于系统的需求,那么 load averages 依然是很好的指标。

最后引用 kernel/sched/loadavg.c 头部的注释来结束吧。

  • This file contains the magic bits required to compute the global loadavg
  • figure. Its a silly number but people think its important. We go through
  • great pains to make it work on big machines and tickless kernels.

转载于:https://www.cnblogs.com/Irving/p/9441553.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/250990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jsp+Servlet+MYSQL注册登录案例(界面难看,ε=(´ο`*)))唉)

注册登录界面尤为常见&#xff0c;我的界面尤为难看&#xff0c;勉为其难的写吧&#xff0c;前端不熟就是这样。。。 这个案例运用到了: 1.Jsp动态页面--->动态页面 2.Servlet逻辑判断后台---->实现界面与数据库/业务的连接&#xff0c;简而言之&#xff0c;起承转合。PS…

ES6-15 map与set

Promise、Proxy、Map、Set这些ES6新增的api无法用babel实现语法降级&#xff0c;需要使用到polyfill Set 成员是唯一的&#xff0c;不能重复有iterator接口&#xff0c;可迭代具有iterator接口的所有类型&#xff0c;都能作为new Set()的参数&#xff0c;如类数组、数组 con…

jquery --- DOM操作、表单元素的初始化

1.获取ul里第2个li节点: var $li_two $("ul li:eq(1)"); // 获取该节点的内容 var $li_two_txt $li_two.text();2.获取p元素节点的title属性: var $para $("p"); var p_title $para.attr("title");3.创建2个li节点,并添加道ul中: var $li…

Jquery中post与get之间的区别详细介绍

1:GET访问浏览器认为是等幂的 GET访问浏览器认为是等幂的&#xff0c;就是一个相同的URL只有一个结果&#xff0c;相同是指整个URL字符串完全匹配。所以&#xff0c;第二次访问的时候&#xff0c;如果URL字符串没变化 浏览器是直接拿出了第一次访问的结果&#xff1b; POST则认…

LeetCode 424. Longest Repeating Character Replacement

原题链接在这里&#xff1a;https://leetcode.com/problems/longest-repeating-character-replacement/description/ 题目&#xff1a; Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at mo…

ES6-16 WeakMap与WeakSet、proxy与reflect

WeakMap/WeakSet 原型上不存在遍历方法(没有部署iterator接口)成员只能是对象垃圾回收机制不考虑对成员对象的应用 WeakSet/WeakMap 中的对象都是弱引用&#xff0c;即垃圾回收机制不考虑 WeakSet 对该对象的引用&#xff0c;也就是说&#xff0c;如果其他对象都不再引用该对象…

jquery--- 属性和样式的操作 设置和获取HTML、文本和值、焦点事件

1.获取p元素的title属性: var title $("p").attr("title");2.给p元素加title属性(值为:栗子)和date属性(值为:2019/7/15): $("p").attr("title":"栗子", "date":"2019/7/15");3.删除p中的title属性:…

day9

前方高能---初识函数 一. 什么是函数 函数:对代码块和功能的封装和定义. 二. 函数的定义,函数名,函数体,以及函数的调用 def 函数名(): 函数体 函数体:就是函数被执行之后要执行的代码. 三, 函数的返回 执行完函数之后,我们可以使用return来返回结果. 函数中return的使用: 1.函…

MySQL 数据库索引

数据库索引在数据库中、索引使数据库程序无须对整个表进行全表扫描就可以在其中找到所需的数据&#xff1b;数据库中的索引是某个表中一列或者若干列值的集合、以及物理标识这些值的数据页的逻辑指针清单&#xff1b;MySQL 索引的增删查SQL 语句效率的分析索引的作用&#xff1…

ES6-17 class与对象

class 模拟类的方式语法糖&#xff08;把以前的写法换了一个方式&#xff09; 类内部的方法是不可枚举的 ES5用Object.assign拓展的原型属性是可枚举的 function Point(x, y) {this.x x;this.y y; } // 这样定义的原型上方法eat\drink是可枚举的 Point.prototype Object…

8.8 正睿暑期集训营 Day5

目录 2018.8.8 正睿暑期集训营 Day5总结A 友谊巨轮(线段树 动态开点)B 璀璨光滑C 构解巨树考试代码ABC2018.8.8 正睿暑期集训营 Day5时间&#xff1a;3.5h(实际)期望得分&#xff1a;602020实际得分&#xff1a;202020 比赛链接这里也有一些 总结 线段树&#xff01;&#xff0…

算法 --- 二叉树的最大深度

思路: 1.二叉树的深度,等于Max(左子树最大深度,右子树最大深度) 1 2.节点不存在时,此时的深度为0 3.当节点存在,左右子树不存在时(此时为叶子节点) 返回1 /*** Definition for a binary tree node.* function TreeNode(val) {* this.val val;* this.left this.righ…

ES6-18/19 异步的开端-promise

ES6-18异步的开端-promise ES6-19 promise的使用方法和自定义promisify try catch只能捕获同步异常&#xff0c;不能捕获异步的 等待所有异步都执行完&#xff0c;打印结果&#xff0c;比较笨拙的方法&#xff0c;在每个异步操作加arr.length 3 && show(arr) Promis…

leetcode35 C++ 4ms 搜索插入位置

class Solution { public:int searchInsert(vector<int>& nums, int target) {for(int i 0;i<nums.size();i){if(nums[i] > target){return i;}}return nums.size()-1;} }; 转载于:https://www.cnblogs.com/theodoric008/p/9449049.html

OpenCV-Python 中文教程(搬运)目录

OpenCV-Python 中文教程 OpenCV官方教程中文版&#xff08;For Python&#xff09; OpenCV2-Python-Tutorials 段力辉 译 说明&#xff1a;搬运自linux公社pdf文件&#xff0c;粗略搬运&#xff0c;仅作个人笔记参考&#xff0c;有时间再美化 部分文件参考&#xff1a; https:/…

算法 --- 平衡二叉树

解题思路: 1.首先写一个返回深度的函数d 2.写一个遍历函数t 3.在t中首先判断,r是否为空(为空则此时就是平衡二叉树,返回true),然后判断是否为叶子节点(r.left null && r.right null)若是则返回true,最后判断,其左子树的深度与右子树的深度之差是否大于1.若是则返回fal…

【co】ES6-20/21 iterator与generator

ES6-20 iterator与generator ES6-21 async与await、ES6的模块化 try catch不能捕获异步异常 try catch是同步代码 try {setTimeout(() > {console.log(a)}) } catch (e) {console.log(e) }iterator 内部迭代器&#xff1a;系统定义好的迭代器接口&#xff08;如数组Symbol…

嵌入式系统UBOOT

一个完整的嵌入式linux系统包含4部分内容&#xff1a;Bootloader、Parameters、Kernel、Root File System。3、4、5、6部分详细介绍了这4部分的内容&#xff0c;这是Linux底层软件开发人员应该掌握的。通过学习这些章节&#xff0c;您可以详细了解到如何在一个裸板上裁减、移植…

驱动芯片

一 LED驱动芯片&#xff1a; 1.1 TM1640:16位数码管驱动芯片&#xff0c;2线制控制&#xff08;CLK/DIN&#xff09;,SCLK低电平时DIN输入&#xff0c;而SCLK高电平时保持DIN保持不变&#xff1b;开始传输&#xff1a;SCLKH时DIN由高变低&#xff0c;停止传输SCLKH时DIN由由低变…

jquery --- 控制元素的隐藏/显示

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> </head> <body> <div id"panel"><h5 class"head">什么是jquery?</h5><div class"content" style"display:non…