Shared by suchasplus
好强大的细节
原文作者:Dr. Neil Gunther
原文链接:UNIX® Load Average Part 1: How It Works
译者:dliang
UNIX® 的平均负载 第一部分 :如何工作
作者:Dr. Neil Gunther,
Performance Dynamics Company
为了正确查看数学符号,请检查这里 ,然后再继续。
你曾经想知道这三个在UNIX®平均负荷(LA)报告中出现的数字是如何计算出来的?
这个TeamQuest在线栏说明如何做以及如何重组平均负载(LA)可以得到更好的容量规划。 但首先,请测试您的知识,在平均负载三胞胎"LA Triplets"测验。
在这两个系列部分我要探索平均数在性能分析与容量规划中的作用。 平均数有许多表现形式,例如,算术平均(通常使用的) ,移动平均线(通常在财务规划中采用) ,几何平均数(用于规格CPU的性能衡量 ) ,调和平均数(没有足够应用) ,等等。
更重要的是,我们将看到随时间推移的平均数或者依赖时间的平均数。 一个依赖时间的平均数的具体例子是在某些Unix命令中出现的平均负荷指标(load average metric)。 在第1部分我们将看看平均负荷是如何被计算出来的。 第2部分中我将它与其他均适用于容量规划和性能分析的技术进行比较。 本文假设你不熟悉Unix命令,因此我将首先回顾一些命令,它们都能显示平均负荷指标。直到第4部分 ,我们会投入到UNIX的内核代码中去,并且完成所有的工作。
1 Unix命令
其实,平均负载不是一个传统意义中的UNIX命令。相反,它是一个嵌入式的指标,显示在其他Unix命令如uptime和procinfo的输出中。这些命令通常是被UNIX的系统管理员用来观察系统资源消耗的。 让我们来仔细看看其中一些命令。
普通的ASCII文本格式出现在各种UNIX的命令中。 以下是一些常见的例子。
这个uptime外壳命令产生下列输出:
[pax:~]% uptime 9:40am up 9 days, 10:36, 4 users, load average: 0.02, 0.01, 0.00 |
它显示自从上次系统重启以来,活动的用户进程数量和所谓的平均负荷指标(load average)。
在Linux系统上,procinfo命令产生以下输出:
[pax:~]% procinfo Linux 2.0.36 (root@pax) (gcc 2.7.2.3) #1 Wed Jul 25 21:40:16 EST 2001 [pax] Memory: Total Used Free Shared Buffers Cached Mem: 95564 90252 5312 31412 33104 26412 Swap: 68508 0 68508 Bootup: Sun Jul 21 15:21:15 2002 Load average: 0.15 0.03 0.01 2/58 8557 ... |
平均负载指标出现在这个输出的左下角。
w(ho)命令产生下列输出:
[pax:~]% w 9:40am up 9 days, 10:35, 4 users, load average: 0.02, 0.01, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT mir ttyp0 :0.0 Fri10pm 3days 0.09s 0.09s bash neil ttyp2 12-35-86-1.ea.co 9:40am 0.00s 0.29s 0.15s w ... |
请注意,第一行的输出与uptime命令的输出相同。
top命令是最近加入到UNIX命令集中的,它通过计算进程消耗CPU的时间来给进程排名。它产生下列输出:
4:09am up 12:48, 1 user, load average: 0.02, 0.27, 0.17 58 processes: 57 sleeping, 1 running, 0 zombie, 0 stopped CPU states: 0.5% user, 0.9% system, 0.0% nice, 98.5% idle Mem: 95564K av, 78704K used, 16860K free, 32836K shrd, 40132K buff Swap: 68508K av, 0K used, 68508K free 14508K cched PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND 5909 neil 13 0 720 720 552 R 0 1.5 0.7 0:01 top 1 root 0 0 396 396 328 S 0 0.0 0.4 0:02 init 2 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 kflushd 3 root -12 -12 0 0 0 SW< 0 0.0 0.0 0:00 kswapd ... |
所有这些命令,请注意,输出中都有三个数字报告平均负载。相当普遍的是,这些数字显示出从左至右的降序。但是有时,又是升序排列,正如上面的输出。
1.2 图形输出
平均负荷也可以显示为一个时间序列一样,在这里显示的是工具ORCA的输出。
图1 :ORCA3日平均负载图。
虽然这种直观辅助工具帮助我们看到,绿色的曲线更spikey和比红色曲线变化更大,它使我们能够看到一天的完整的数据,目前尚不清楚这对能力规划或性能分析有多大作用。 我们需要了解的是平均负载指标的定义和计算方法。
2 它是什么?
那么,这些不同的命令确切地说明了什么是平均负载么? 让我们来看看官方的UNIX文档。
2.1 UNIX操作手册
[pax:~]% man "load average" No manual entry for load average |
哎呀!没有手册说明!平均负载是其他命令的内嵌输出,所以没有单独的手册文档。好吧,让我们看看uptime命令的文档,能否从中获得写帮助。
... DESCRIPTION uptime gives a one line display of the following informa- tion. The current time, how long the system has been run- ning, how many users are currently logged on, and the sys- tem load averages for the past 1, 5, and 15 minutes. ... uptime产生一条信息,包括当前时间,系统连续运行时间,当前登录用户 |
所以那三个数字指标,表示了“过去1、5、15分钟内的系统平均负载。”
|
但是,文档中仍然回避了什么是负载(load)的问题。
2.2 什么是大师不得不说的
让我们转向一些UNIX热点问题来看一看。
Tim O'Reilly and Crew
《UNIX超级工具》(UNIX Power Tools [])这本书,在726页告诉我们,CPU是:
|
这是令人鼓舞的!无论如何,它帮助我们解释了衡量的内容:活动进程数量。在720页 39.07 检查系统的负载:uptime 中这样说:
|
嗯... 这个数字“ 3 ”是怎么来的? 和这三个平均数( 1 , 5 , 15分钟) ,他们指的是什么?
Adrian Cockcroft 在 Solaris
在Sun性能和调优(Sun Performance and Tuning)[]中的97页中的一段:搞懂和使用平均负载,Adrian Cockcroft叙述到:
|
所以,即便是Sun的“大男孩们”做错了什么。然而,这样的想法,将平均负载与CPU运行队列联系在一起是重要的观点。
O'Reilly 等. 还注意到一些使用平均负载的潜在陷阱。
|
CPU被挂钩2100秒后进程被杀死 CPU在余下的1500秒后保持静默
3.2 采样过程
正如作者[]关于Linux内核的解释,因为我们的测试进程是CPU绑定的,他们将处在TASK_RUNNING状态。 这意味着它们是:
Linux内核还检查是否有任何任务处在短期睡眠状态,称为TASK_UNINTERRUPTIBLE状态。 如果有,它们也包括在平均负载的采样中。它们都没有在我们的负载测试中。
下面的源代码片段显示如何做到这一点的更详细资料。
600 * Nr of active tasks - counted in fixed-point numbers 601 */ 602 static unsigned long count_active_tasks(void) 603 { 604 struct task_struct *p; 605 unsigned long nr = 0; 606 607 read_lock(&tasklist_lock); 608 for_each_task(p) { 609 if ((p->state == TASK_RUNNING || 610 (p->state & TASK_UNINTERRUPTIBLE))) 611 nr += FIXED_1; 612 } 613 read_unlock(&tasklist_lock); 614 return nr; 615 } |
所以,uptime每5秒钟的采样是Linux内核的内在时基更新平均负载的计算。
3.3 测试结果
实验结果的图示在图2。图中的颜色并不与图1中的具有相同的意思。
图 2: Linux 平均负载测试结果。
相比之下,这是如何一个单独繁忙循环运行在一个单CPU的Solaris系统中的图示。
Figure 3: Solaris 平均负载测试结果。
你应该原谅这个跳出来的“负载”就是CPU利用率的结论。 随着Linux的测试结果表明,当两个繁忙的进程在运行,在单个CPU的最高负载是2(而不是1 )。因此,负载不等于CPU利用率。
从另一个角度来看,图2类似于电容器的充电和放电过程
图 4: 电容的充电(charge)及放电(discharge)过程.
现在让我们进入Linux内核 ,看看这些平均负载的数字是如何产生的。
unsigned long avenrun[3]; 624 625 static inline void calc_load(unsigned long ticks) 626 { 627 unsigned long active_tasks; /* fixed-point */ 628 static int count = LOAD_FREQ; 629 630 count -= ticks; 631 if (count < 0) { 632 count += LOAD_FREQ; 633 active_tasks = count_active_tasks(); 634 CALC_LOAD(avenrun[0], EXP_1, active_tasks); 635 CALC_LOAD(avenrun[1], EXP_5, active_tasks); 636 CALC_LOAD(avenrun[2], EXP_15, active_tasks); 637 } 638 } |
倒计时是在5赫兹的LOAD_FREQ中进行的,这是多长时间呢?
1 HZ = 100 ticks 5 HZ = 500 ticks 1 tick = 10 milliseconds 500 ticks = 5000 milliseconds (or 5 seconds) |
所以,5赫兹指CALC_LOAD每5秒钟被调用一次。
4.1 魔术数字
函数CALC_LOAD其实是一个定义在sched.h文件中的宏。
58 extern unsigned long avenrun[]; /* Load averages */ 59 60 #define FSHIFT 11 /* nr of bits of precision */ 61 #define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */ 62 #define LOAD_FREQ (5*HZ) /* 5 sec intervals */ 63 #define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */ 64 #define EXP_5 2014 /* 1/exp(5sec/5min) */ 65 #define EXP_15 2037 /* 1/exp(5sec/15min) */ 66 67 #define CALC_LOAD(load,exp,n) \ 68 load *= exp; \ 69 load += n*(FIXED_1-exp); \ 70 load >>= FSHIFT; |
一个值得注意并令人好奇的是这些数字: 1884, 2014, 2037。 代表什么? 如果我们看一下这段代码的开头,我们会知道:
/* 49 * These are the constant used to fake the fixed-point load-average 50 * counting. Some notes: 51 * - 11 bit fractions expand to 22 bits by the multiplies: this gives 52 * a load-average precision of 10 bits integer + 11 bits fractional 53 * - if you want to count load-averages more often, you need more 54 * precision, or rounding will get you. With 2-second counting freq, 55 * the EXP_n values would be 1981, 2034 and 2043 if still using only 56 * 11 bit fractions. 57 */ 这是用来假冒定点平均负载计数的常量。
11位小数通过乘法扩大到22位:这样有了一个精度为10位整数和11为小数的平均负载数。
如果你想更频繁地记录平均负载,你就需要更大的精度,否则会四舍五入。使用2秒的计数
周期,如果仍然使用11位小数,EXP_n的数值将是1981,2034和2043。 |
这些魔术数字是使用定点(而不是浮点)的结果。
使用1分钟取样作为一个例子,转换的exp(5/60)到11位精度的二进制是这样的:
|
(1) |
但是EXP_M表示了逆运算exp(-5/60)。因此,我们能从下面的公式中直接计算出那些魔术数字。
|
(2) |
M=1代表分钟采样周期。表1整理了部分结果。
T | EXP_T | Rounded |
5/60 | 1884.25 | 1884 |
5/300 | 2014.15 | 2014 |
5/900 | 2036.65 | 2037 |
2/60 | 1980.86 | 1981 |
2/300 | 2034.39 | 2034 |
2/900 | 2043.45 | 2043 |
表 1: 平均负载的魔术数字
这些数字在上述的内核注释中得到了充分的认同。使用定点运算大概是出于性能考虑,因为计算能在内核空间中进行,而不是用户空间。
仍然有一个问题,像exp(5/60)这样的比值是如何来的?
4.2 魔法揭示
用1分钟平均数举例,CALC_LOAD等同于数学公式:
|
(3) |
如果我们认为n=0,公式(3) 简化为:
|
(4) |
如果我们迭代公式(4),在t = t0 和 t = T 之间,我们得到:
|
(5) |
这就是指数衰变,就像我们在图2中看到的从时间t0 = 2100到tT = 3600的一样。
Conversely, when n = 2 as it was in our experiments, the load average is dominated by the second term such that:
相反,就像在我们的实验中一样,当n=2时,平均负载被第二种因素主宰了:
|
(6) |
这是一个单调增函数,就像我们在图2中的t0 = 0到tT= 2100中看到的一样。
5 综述
因此,我们学到了什么? 那三个平均负载三胞胎(LA Triplets)中无伤大雅的数字背后有着令人惊奇的奥秘。
这三个数字为您提供某种形式的有关系统在最近的过去(1分钟),过去( 5分钟)和遥远的过去( 15分钟)所做事情的一些信息。
你如果试过了(LA Triplets)问答就会发现这样的问题:
如果你试图使用它们进行容量规划,这些继承的限制是非常重要的。我会有更详细的解释在平均负载第二部分:不是你的平均的平均数。
参考文献
[BC01]D. P. Bovet and M. Cesati. Understanding the Linux Kernel. O'Reilly & Assoc. Inc., Sebastopol, California, 2001.
[Coc95]A. Cockcroft. Sun Performance and Tuning. SunSoft Press, Mountain View, California, 1st edition, 1995.
[Gun01]N. J. Gunther. Performance and scalability models for a hypergrowth e-Commerce Web site. In R. Dumke, C. Rautenstrauch, A. Schmietendorf, and A. Scholz, editors,Performance Engineering: State of the Art and Current Trends, volume # 2047, pages 267-282. Springer-Verlag, Heidelberg, 2001.
[POL97]J. Peek, T. O'Reilly, and M. Loukides. UNIX Power Tools. O'Reilly & Assoc. Inc., Sebastopol, California, 2nd edition, 1997.
四月 2009 | ||||||
一 | 二 | 三 | 四 | 五 | 六 | 日 |
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |