服务器负载均衡——加权轮询调度算法(WeightedRound-Robin)以及负载均衡算法的C++简单实现

权重轮询

1、轮询算法(Round-Robin)

轮询算法是最简单的一种负载均衡算法。它的原理是把来自用户的请求轮流分配给内部的服务器:从服务器1开始,直到服务器N,然后重新开始循环

//其中currentindex是当前位置,totalserver是所有服务器节点数量。
    int Server round() {  
        currentIndex = (currentIndex + 1) % totalServer;  //返回服务器的索引
        return servers.get(currentIndex);  //通过索引,建立连接
    }  

特征:

  • 简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度
  • 假设所有服务器的处理性能都相同,不关心每台服务器的当前连接数和响应速度。
  • 当请求服务间隔时间变化比较大时,轮询算法容易导致服务器间的负载不平衡。
  • 适合于服务器组中的所有服务器都有相同的软硬件配置并且平均服务请求相对均衡的情况。

2、加权轮询算法(WeightedRound-Robin)

轮询算法并没有考虑每台服务器的处理能力,实际中可能并不是这种情况。由于每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。

所以,加权轮询算法的原理就是:根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。

1、举例说明:

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

服务每收到7个客户端的请求,会把其中的1个转发给后端a,把其中的2个转发给后端b,把其中的4个转发给后端c

过程如下:

  • 每当有请求到来时,就依次从该序列中取出下一个服务器用于处理该请求。
  • 每收到7个客户端的请求,会把其中的1个转发给后端a,把其中的2个转发给后端b,把其中的4个转发给后端c。
  • 收到的第8个请求,重新从该序列的头部开始轮询。

总之,加权轮询算法要生成一个服务器序列,该序列中包含n个服务器。n是所有服务器的权重之和。在该序列中,每个服务器的出现的次数,等于其权重值

并且,生成的序列中,服务器的分布应该尽可能的均匀。

  • 比如序列{a, a, a, a, a, b, c}中,前五个请求都会分配给服务器a,这就是一种不均匀的分配方法,更好的序列应该是:{a,a, b, a, c, a, a}

2、算法流程:
假设有一组服务器 S = {S0, S1, …, Sn-1} ,有相应的权重,变量i表示上次选择的服务器,

原理:

  • 在服务器数组S中,首先计算所有服务器权重的最大值max(S),以及所有服务器权重的最大公约数gcd(S)

  • index表示本次请求到来时,选择的服务器的索引,初始值为-1;current_weight表示当前调度的权值,初始值为max(S)

  • 当请求到来时,从index+1开始轮询服务器数组S,找到其中权重大于current_weight的第一个服务器,用于处理该请求。记录其索引到结果序列中。

  • 在轮询服务器数组时,如果到达了数组末尾,则重新从头开始搜索,并且减小current_weight的值:current_weight -= gcd(S)。如果current_weight等于0,则将其重置为max(S)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include<algorithm>
#include<map>

using namespace std;
#define BUFFER_SIZE 1024

struct srv_info {
    srv_info() {
        ip  = new char[BUFFER_SIZE];
        weight = 0;
    }

    char* ip;
    int weight;
};

static vector<srv_info> server;		//服务器信息
int getGcd(int a, int b);		    //获得两个数的最大公约数
int getMaxGcd();                    //获得所有数的最大公约数
int getMaxWeight();				//获得所有服务器中的最大权值
int getSelectServer(srv_info* serverInfo, int serverNum, int maxGcd, int maxWeight, int *curWeight,int *serverIndex); //轮询调度

int main(int argc, char **argv) {
    ////填充服务器IP和权重
    server.clear();
    char tmp[BUFFER_SIZE];
    struct srv_info sinfo;
    
    const char* ip_x = "192.168.0.10";
   
    memset(tmp, '\0', BUFFER_SIZE);
    sprintf(tmp, "%s%d", ip_x, 1);
    memcpy(sinfo.ip, tmp, BUFFER_SIZE);
    sinfo.weight = 1;
    server.push_back(sinfo);
  
    memset(tmp, '\0', BUFFER_SIZE);
    sprintf(tmp, "%s%d", ip_x, 2);
    memcpy(sinfo.ip, tmp, BUFFER_SIZE);
    sinfo.weight = 2;
    server.push_back(sinfo);

    memset(tmp, '\0', BUFFER_SIZE);
    sprintf(tmp, "%s%d", ip_x, 3);
    memcpy(sinfo.ip, tmp, BUFFER_SIZE);
    sinfo.weight = 3;
    server.push_back(sinfo);

 

    memset(tmp, '\0', BUFFER_SIZE);
    sprintf(tmp, "%s%d", ip_x, 4);
    memcpy(sinfo.ip, tmp, BUFFER_SIZE);
    sinfo.weight = 4;
    server.push_back(sinfo);

    ////输出服务器信息
    printf("server count: %ld\n", server.size());
    for (size_t i = 0; i < server.size(); i++) {
        printf("%s	weight: %d\n", server[i].ip, server[i].weight);
    }
   printf("====================================\n");

    int serverNum = int(server.size());	//服务器个数
    int maxGcd = getMaxGcd(); //最大公约数
    int maxWeight = getMaxWeight(); //最大权重值

    srv_info serverInfo;
    int retIndex = -1;
    int count = 0;
    map<int,int> mapIndex2Count;
    map<int, int>::iterator iter;
    int curWeight = 0;			//当前调度的权值
    int serverIndex = -1;		//上一次选择的服务器 

    for (int i = 0; i < 100; i++) { //调度100次
        retIndex = getSelectServer(&serverInfo, serverNum, maxGcd, maxWeight, &curWeight, &serverIndex);
        if (retIndex == -1) {
            continue;
        }

        printf("Ip: %s, Weight: %d, Index: %d\n", serverInfo.ip, serverInfo.weight, serverIndex);

        iter = mapIndex2Count.find(retIndex);
        if (iter != mapIndex2Count.end()) {
            count = mapIndex2Count[retIndex];
            mapIndex2Count[retIndex] = ++count;
        } else {
            mapIndex2Count[retIndex] = 1;
        }
    }

    printf("====================================\n");

    for (size_t i = 0; i < server.size(); i++) {
        printf("ip:%s, weight:%d, called %d times\n", server[i].ip, server[i].weight, mapIndex2Count[i]);
    }
   return 0;
}


int getGcd(int a, int b) {
    int c = 0;
    while(b>0) {
        c = b;
        b = a%b;
        a = c;
    }
    return a;
}

 

//获取所有权重的最大公约数
int getMaxGcd() {
    int res = server[0].weight;
    int curMax=0, curMin=0;
    for (size_t i = 0; i < server.size(); i++)
    {
        curMax = int(max(res, server[i].weight)); //比较上次计算结果和本次权重值,取两个数中的较大者
        curMin = int(min(float(res), float(server[i].weight))); //比较上次计算结果和本次权重值,取两个数中的较小者
        res = getGcd(curMax, curMin); //本次计算结果,获取两个数的最大公约数
    }
    return res;
}

int getMaxWeight() {
    int max = 0;
    for (size_t i = 0; i < server.size(); i++) {
        if (server[i].weight > max) {
            max = server[i].weight;
        }
    }

    return max;

}

 

/**

 * 算法流程:

 * 假设有一组服务器 S = {S0, S1, …, Sn-1} ,有相应的权重,变量serverIndex表示上次选择的服务器,

 * 权值curWeight初始化为0,serverIndex初始化为-1 ,当第一次的时候,取权重值最大的那个服务器.

 * 通过权重值的不断递减,寻找适合的服务器返回,直到轮询结束,权值返回为0.

 */

int getSelectServer(srv_info* serverInfo, int serverNum, int maxGcd, int maxWeight, int *curWeight,int *serverIndex) {
    while (true) {
        *serverIndex = (*serverIndex + 1) % serverNum;
        if (*serverIndex == 0) {
            *curWeight = *curWeight - maxGcd;
            if (*curWeight <= 0) {
                *curWeight = maxWeight;
                if (*curWeight == 0) {
                    return -1;
                }
            }
        }
        if (server[*serverIndex].weight >= *curWeight) {
            serverInfo->weight = server[*serverIndex].weight;
            memcpy(serverInfo->ip, server[*serverIndex].ip, BUFFER_SIZE);
            return *serverIndex;
        }
    }
}

执行结果如下:


server count: 4

192.168.0.104	weight: 1

192.168.0.104	weight: 2

192.168.0.104	weight: 3

192.168.0.104	weight: 4

====================================

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

Ip: 192.168.0.104, Weight: 1, Index: 0

Ip: 192.168.0.104, Weight: 2, Index: 1

Ip: 192.168.0.104, Weight: 3, Index: 2

Ip: 192.168.0.104, Weight: 4, Index: 3

====================================

ip:192.168.0.104, weight:1, called 10 times

ip:192.168.0.104, weight:2, called 20 times

ip:192.168.0.104, weight:3, called 30 times

ip:192.168.0.104, weight:4, called 40 times

参考

1、https://www.cnblogs.com/wsw-seu/p/11336634.html
2、https://blog.csdn.net/chinawangfei/article/details/83961046

猜你喜欢

转载自blog.csdn.net/JMW1407/article/details/107787546
今日推荐