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;
那麼,調度算法可以描述爲:
- 初始每個實例 i 的 當前有效權重 CWi 爲 配置權重 Wi,並求得配置權重和 weightSum;
- 選出 當前有效權重 最大 的實例,將 當前有效權重 CWi 減去所有實例的 權重和 weightSum,且變量 currentPos 指向此位置;
- 將每個實例 i 的 當前有效權重 CWi 都加上 配置權重 Wi;
- 此時變量 currentPos 指向的實例就是需調度的實例;
- 每次調度重複上述步驟 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;
}