负载均衡算法 : 加权轮询

1 加权轮询算法背景

       轮询算法没有考虑每台服务器的处理能力,实际情况是每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。所以,加权轮询算法的原理就是:根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能接受相应权值数的服务请求。

首先看一个简单的Nginx负载均衡配置。

http {
    upstream cluster {
    server a weight=1;
    server b weight=2;
    server c weight=4;
    }
...
}

   按照上述配置,Nginx每收到7个客户端的请求,会把其中的1个转发给后端a,把其中的2个转发给后端b,把其中的4个转发给后端c。

2 加权轮询算法描述

       假设有 N 台实例 S = {S1, S2, …, Sn},配置权重 W = {W1, W2, …, Wn},有效权重 CW = {CW1, CW2, …, CWn}。每个实例 i 除了存在一个配置权重 Wi 外,还存在一个当前有效权重 CWi,且 CWi 初始化为 Wi;指示变量 currentPos 表示当前选择的实例 ID,初始化为 -1;所有实例的配置权重和为 weightSum;

那么,调度算法可以描述为:

  1. 初始每个实例 i 的 当前有效权重 CWi 为 配置权重 Wi,并求得配置权重和 weightSum;
  2. 选出 当前有效权重 最大 的实例,将 当前有效权重 CWi 减去所有实例的 权重和 weightSum,且变量 currentPos 指向此位置;
  3. 将每个实例 i 的 当前有效权重 CWi 都加上 配置权重 Wi;
  4. 此时变量 currentPos 指向的实例就是需调度的实例;
  5. 每次调度重复上述步骤 2、3、4;

上述 3 个服务,配置权重和 weightSum 为 7,其调度过程如下:

请求 选中前的当前权重 currentPos 选中的实例 选中后的当前权重
1 {4, 2, 1} 0 a {-3, 2, 1}
2 {1, 4, 2} 1 b {1, -3, 2}
3 {5, -1, 3} 0 a {-2, -1, 3}
4 {2, 1, 4} 2 c {2, 1,-3 }
5 {6, 3, -2} 0 a {-1, 3, -2}
6 {3, 5, -1} 1 b {3, -2, -1}
7 {7, 0, 0} 0 a {0, 0, 0}

     生成的序列是{a, b, a, c, a, b, a},发给后端的服务都分散开了,不在连续了。

3 代码实现

#include <iostream>
#include <string>
#include <vector>
#include <numeric>

using namespace std;

typedef struct
{
	int weight;
	int cur_weight;
	string  name;
}server;


vector<server> initServers(vector<string>&  names, vector<int> weights)
{
	int i = 0;
	vector<server> ss(weights.size());

	for (i = 0; i < weights.size(); i++)
	{
		ss[i].weight = weights[i];
		ss[i].name = names[i];
		ss[i].cur_weight = 0;
	}
	return ss;
}

int getNextServerIndex(vector<server>& ss, int total)
{
	int i;
	int index = -1;

	for (i = 0; i < ss.size(); i++)
	{
		ss[i].cur_weight += ss[i].weight;

		if (index == -1 || ss[index].cur_weight < ss[i].cur_weight)
		{
			index = i;
		}
	}

	ss[index].cur_weight -= total;
	return index;
}


void wrr_nginx(vector<server>&ss, vector<int > weights)
{
	int i = 0;
	int index = -1;
	int sum = accumulate(weights.begin(),weights.end(),0);

	for (i = 0; i < sum; i++)
	{
		index = getNextServerIndex(ss, sum);
		printf("%s ", ss[index].name.c_str());
	}
	printf("\n");
}

int main()
{
	int i = 0;
	vector<int > weights = { 4, 2, 1 };
	vector<string > SerVerNames = { "a", "b", "c" };
	
	vector<server> ss = initServers(SerVerNames, weights);

	printf("server is : \n ");
	for (i = 0; i < ss.size(); i++)
	{
		printf("server %s  weight = %d\n ", ss[i].name.c_str(), ss[i].weight);
	}
	printf("\n");

	printf("\nwrr_nginx sequence is : ");
	wrr_nginx(ss, weights);

	system("pause");
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章