负载均衡的计算方法和含义

我们在运行top 或者uptime时,会计算当前系统的负载平衡。
当前系统的负载平衡是看我们cpu对于当前执行任务的一个执行情况。同时也判断我们系统的任务
对于cpu的需求情况。
这句话是对于负载平衡的一个很好的总结:

The CPU percentage shows us how much the cars are using the freeway, but the load averages show us the whole picture, including pent-up demand.

以下是我收集的负载平和的计算方法
负载的查看

在Linux系统中,使用uptime、w和top命令都可以查看负载,或者直接通过cat /proc/loadavg查看。

比如说uptime命令:

20:56:33 up 22 min, 3 users, load average: 0.39, 0.25, 0.10

可以看到有三个值,这三个值分别表示:

前1分钟系统的平均负载
前5分钟系统的平均负载
前15分钟系统的平均负载

下面就来看看负载的含义。
负载的含义

负载的含义是运行队列的平均长度。

具体而言,对于Linux系统,其统计了最近1分钟、最近5分钟、最近15分钟处于running或者uninterruptible sleep状态的进程数。

文末参考资料里给出了一个车道的例子进行类比,这儿就不赘述了。举几个例子:

负载为0.5,表示CPU有平均一半的时间是空闲的
负载为1,这时就表示CPU被充分利用了
负载为2,则表示负载过大,有一半的任务在等待CPU执行

一般认为负载为0.7是警戒线。
负载与多处理器

对于多处理器,相当于多车道。比如对于双处理器,那么负载为2才算满。 可以简单地将负载除以CPU核心数换算成单处理的情况。
负载与CPU使用率

文末参考资料中提到:

The CPU percentage shows us how much the cars are using the freeway, but the load averages show us the whole picture, including pent-up demand.

相比于CPU使用率,负载可能展示更多的信息,即CPU的需求量。
负载和多线程

Wikipedia提到在不同的Unix系统中多线程负载的计算方式有很多种,比如线程与核实体间不同的模型就有所不同。而在Linux系统中每个线程应该都是独立计算的。
负载的计算

我并不了解统计学等知识,以下只是个人一些粗浅的理解。

负载计算原理是统计学的EWMA(Exponentially Damped/Weighted Moving Average),利用指数衰减函数递推出当前序列平均值。

Wikipedia里提到:

Hence, the 1-minute load average consists of 63% (more precisely: 1 - 1/e) of the load from the last minute and 37% (1/e) of the average load since start up, excluding the last minute. For the 5- and 15-minute load averages, the same 63%/37% ratio is computed over 5 minutes and 15 minutes respectively. Therefore, it's not technically accurate that the 1-minute load average only includes the last 60 seconds of activity (it actually includes 37% of the activity from the past), but it is correct to state that it includes mostly the last minute.

即统计计算出一段时间的负载,其本质是计算均值。比如说:

    要计算——最近x分钟负载:$la_{-x}$
    假设已知——自系统启动到x分钟前的负载为:$la_{+x}$
    假设可以得到——近x分钟的运行的任务数为:$n_x$

那么 l a − x = l a + x t i m e s ( e − 1 ) + n x t i m e s ( 1 − e − 1 ) la_{-x} = la_{+x} times (e^{-1}) + n_x times (1-e^{-1}) lax=la+xtimes(e1)+nxtimes(1e1) l a − x = l a + x t i m e s 0.37 + n x t i m e s 0.63 la_{-x} = la_{+x} times 0.37 + n_x times 0.63 lax=la+xtimes0.37+nxtimes0.63

可以看出 x x x分钟前的负载权重是比较小的,随着时间的推移前面的信息影响会越来越小,直到趋近于0,最近时间的信息影响的比重比较大。

而在Linux系统中,是每间隔 5 H Z 5HZ 5HZ或者 5 秒 5秒 5统计一次运行的任务数,然后计算均值。那么随着时间推移,可以得出这么一个序列:

n 1 , n 2 , n 3 , . . . , n t − 1 , n t n_1, n_2, n_3, ..., n_{t-1}, n_t n1,n2,n3,...,nt1,nt

当前时刻 t t t的Moving Average—— m v t mv_t mvt同样根据 m v t − 1 mv_{t-1} mvt1计算出:

m v t = m v t − 1 t i m e s ( e − l a m b d a ) + n t t i m e s ( 1 − e − l a m b d a ) mv_t = mv_{t-1} times (e^{-lambda}) + n_t times (1-e^{-lambda}) mvt=mvt1times(elambda)+nttimes(1elambda)

对于要统计最近1分钟(60秒)的均值,由于时间间隔为5秒,那么 l a m b d a lambda lambda的取值应为 f r a c 560 frac 5{60} frac560;同理,最近5分钟(300秒)的均值, l a m b d a lambda lambda的取值应为 f r a c 5300 frac 5{300} frac5300;最近15分钟(900秒)的均值, l a m b d a lambda lambda的取值应为 f r a c 5900 frac 5{900} frac5900

下面来看看Linux中如何实现负载的计算。
负载计算的实现

Linux内核中维护了一个Jiffies变量,记录自开机一开经历的Tick数,每次更新Jiffies时系统会调用timer.c中的do_timer();

unsigned long avenrun[3];
static inline void (unsigned long ticks)
{
	unsigned long active_tasks; 
	static int count = LOAD_FREQ;
	count -= ticks;
	if (count < 0) {
		count += LOAD_FREQ;
		active_tasks = count_active_tasks();
		CALC_LOAD(avenrun[0], EXP_1, active_tasks);
		CALC_LOAD(avenrun[1], EXP_5, active_tasks);
		CALC_LOAD(avenrun[2], EXP_15, active_tasks);
	}
}

在sched.h中可以看到上面calc_load()里一些变量、宏的定义:

extern unsigned long avenrun[];	/* Load averages */
#define FIXED_1  (1<<FSHIFT)	/* 1.0 as fixed-point */
#define LOAD_FREQ (5*HZ)	/* 5 sec intervals */
#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) */
#define CALC_LOAD(load,exp,n) 
	load *= exp; 
	load += n*(FIXED_1-exp); 
	load >>= FSHIFT;

可以看到,每次Jiffies+1时调用calc_load(),并不会马上统计计算负载信息,而是等到一个LOAD_FREQ的周期结束,随后又开始新的LOAD_FREQ周期;

通过调用count_active_tasks()可以获得处于running或者uninterruptible sleep状态的进程数;

最后执行三次的CALC_LOAD,分别更新统计的1分钟、5分钟和15分钟的负载信息。

值得一提的就是CALC_LOAD的实现,其本质是将上面的Moving Average计算的式子乘以 2 11 2^{11} 211,最后再除以 2 11 2^{11} 211,采用位运算并且避免了浮点数运算,提高了计算效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值