C++和go實現輪詢排程演算法(Round-Robin Scheduling)
阿新 • • 發佈:2018-12-08
在多臺機器實現負載均衡的時候,經常用到輪詢排程演算法(Round-Robin Scheduling)。
輪詢排程演算法就是:以迴圈的方式,依次將請求排程到不同的伺服器,即每次排程執行i = (i + 1) mod n,並選出第i臺伺服器。
演算法的優點是其簡潔性,它無需記錄當前所有連線的狀態,所以它是一種無狀態排程。
1、演算法流程:
假設有一組伺服器 S = {S0, S1, …, Sn-1} ,有相應的權重,變數i表示上次選擇的伺服器,權值curWeight初始化為0,index初始化為-1 ,當第一次的時候取權值取最大的那個伺服器,通過權重的不斷遞減,尋找適合的伺服器返回,直到輪詢結束,權值返回為0。
2. C++版程式碼實現
#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
3. go語言實現版本
package main
import (
"math"
"fmt"
)
type Servers struct {
service string
weight int
provider string
}
//獲取權重總和
func getSumWeight(serverList []Servers) int {
r := 0
for _, server := range serverList {
r += server.weight
}
return r
}
//獲取兩個數的最大公約數
func getGcd(a int, b int) int {
c := 0
for b>0 {
c = b
b = a%b
a = c
}
return a
}
//獲取所有權重的最大公約數
func getMaxGcd(serverList []Servers) int {
resGcd := serverList[0].weight
for i:=1; i<len(serverList); i++ {
max := int(math.Max(float64(resGcd), float64(serverList[i].weight))) //比較上次計算結果和本次權重值,取兩個數中的較大者
min := int(math.Min(float64(resGcd), float64(serverList[i].weight))) //比較上次計算結果和本次權重值,取兩個數中的較小者
resGcd = getGcd(max, min) //本次計算結果,獲取兩個數的最大公約數
}
return resGcd
}
//獲取所有權重的最大值
func getMaxWeight(s []Servers) int {
m := 0
for _, server := range s {
if server.weight > m {
m = server.weight
}
}
return m
}
func getSelectServer(s []Servers, gcd int, maxWeight int, index *int, cw *int) int {
for {
*index = (*index+1)%len(s)
if *index == 0 {
*cw = *cw - gcd
if *cw <= 0 {
*cw = maxWeight
if *cw == 0 {
return -1
}
}
}
if s[*index].weight >= *cw {
return *index
}
}
}
//按照權重進行分配
func wrr(serverList []Servers) {
maxGcd := getMaxGcd(serverList) //獲取所有權重的最大公約數
maxWeight := getMaxWeight(serverList) //獲取所有權重的最大值
fmt.Println("所有權重的最大公約數: ", maxGcd)
fmt.Println("獲取所有權重的最大值: ", maxWeight)
sumWeight := getSumWeight(serverList) //獲取所有權重的總和
fmt.Println("獲取所有權重的總和: ", sumWeight)
index := -1 //索引值
curWeight := 0 //當前權重
mapProvider2Times := make(map[string]int) //統計結果
for i:=0; i<sumWeight; i++ {
retIndex := getSelectServer(serverList, maxGcd, maxWeight, &index, &curWeight)
if retIndex == -1 {
continue;
}
fmt.Printf("節點名稱:%s,節點權重:%d, 索引值:%d, 當前權重計算結果%d \r\n", serverList[index].provider, serverList[index].weight, index, curWeight)
mapProvider2Times[serverList[index].provider] += 1
}
fmt.Println("統計結果")
for key, value := range mapProvider2Times {
fmt.Printf("名稱: %s, 次數: %d\n", key, value)
}
}
func main() {
serverList := []Servers{
{
service: "cd",
weight:6,
provider:"test1",
},
{
service: "book",
weight:2,
provider: "test2",
},
{
service: "pen",
weight:4,
provider: "test3",
},
}
wrr(serverList)
}
執行結果如下:
所有權重的最大公約數: 2
獲取所有權重的最大值: 6
獲取所有權重的總和: 12
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果6
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果4
節點名稱:test3,節點權重:4, 索引值:2, 當前權重計算結果4
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果2
節點名稱:test2,節點權重:2, 索引值:1, 當前權重計算結果2
節點名稱:test3,節點權重:4, 索引值:2, 當前權重計算結果2
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果6
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果4
節點名稱:test3,節點權重:4, 索引值:2, 當前權重計算結果4
節點名稱:test1,節點權重:6, 索引值:0, 當前權重計算結果2
節點名稱:test2,節點權重:2, 索引值:1, 當前權重計算結果2
節點名稱:test3,節點權重:4, 索引值:2, 當前權重計算結果2
統計結果
名稱: test1, 次數: 6
名稱: test3, 次數: 4
名稱: test2, 次數: 2