負載均衡算法 : 加權輪詢

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;
}

 

 

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