在多台機器實現負載均衡的時候,經常用到輪詢調度算法(Round-Robin Scheduling)。
輪詢調度算法就是以循環的方式依次將請求調度不同的服務器,即每次調度執行i = (i + 1) mod n,並選出第i台服務器。
算法的優點是其簡潔性,它無需記錄當前所有連接的狀態,所以它是一種無狀態調度。
1、算法流程:
假設有一組服務器 S = {S0, S1, …, Sn-1} ,有相應的權重,變量i表示上次選擇的服務器,權值cw初始化為0,i初始化為-1 ,當第一次的時候取權值取最大的那個服務器,通過權重的不斷遞減,尋找適合的服務器返回,直到輪詢結束,權值返回為0
1 import java.math.BigInteger;
2 import java.util.ArrayList;
3 import java.util.HashMap;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.Map.Entry;
7
8 /**
9 * 權重輪詢調度算法(WeightedRound-RobinScheduling)-Java實現
10 * @author huligong
11 * */
12 public class WeightedRoundRobinScheduling {
13
14 private int currentIndex = -1;// 上一次選擇的服務器
15 private int currentWeight = 0;// 當前調度的權值
16 private int maxWeight = 0; // 最大權重
17 private int gcdWeight = 0; //所有服務器權重的最大公約數
18 private int serverCount = 0; //服務器數量
19 private List<Server> serverList; //服務器集合
20
21 /**
22 * 返回最大公約數
23 * @param a
24 * @param b
25 * @return
26 */
27 private static int gcd(int a, int b) {
28 BigInteger b1 = new BigInteger(String.valueOf(a));
29 BigInteger b2 = new BigInteger(String.valueOf(b));
30 BigInteger gcd = b1.gcd(b2);
31 return gcd.intValue();
32 }
33
34
35 /**
36 * 返回所有服務器權重的最大公約數
37 * @param serverList
38 * @return
39 */
40 private static int getGCDForServers(List<Server> serverList ) {
41 int w = 0;
42 for (int i = 0, len = serverList.size(); i < len - 1; i++) {
43 if (w == 0) {
44 w = gcd(serverList.get(i).weight, serverList.get(i + 1).weight);
45 } else {
46 w = gcd(w, serverList.get(i + 1).weight);
47 }
48 }
49 return w;
50 }
51
52
53 /**
54 * 返回所有服務器中的最大權重
55 * @param serverList
56 * @return
57 */
58 public static int getMaxWeightForServers(List<Server> serverList) {
59 int w = 0;
60 for (int i = 0, len = serverList.size(); i < len - 1; i++) {
61 if (w == 0) {
62 w = Math.max(serverList.get(i).weight, serverList.get(i + 1).weight);
63 } else {
64 w = Math.max(w, serverList.get(i + 1).weight);
65 }
66 }
67 return w;
68 }
69
70 /**
71 * 算法流程:
72 * 假設有一組服務器 S = {S0, S1, …, Sn-1}
73 * 有相應的權重,變量currentIndex表示上次選擇的服務器
74 * 權值currentWeight初始化為0,currentIndex初始化為-1 ,當第一次的時候返回 權值取最大的那個服務器,
75 * 通過權重的不斷遞減 尋找 適合的服務器返回,直到輪詢結束,權值返回為0
76 */
77 public Server GetServer() {
78 while (true) {
79 currentIndex = (currentIndex + 1) % serverCount;
80 if (currentIndex == 0) {
81 currentWeight = currentWeight - gcdWeight;
82 if (currentWeight <= 0) {
83 currentWeight = maxWeight;
84 if (currentWeight == 0)
85 return null;
86 }
87 }
88 if (serverList.get(currentIndex).weight >= currentWeight) {
89 return serverList.get(currentIndex);
90 }
91 }
92 }
93
94
95 class Server {
96 public String ip;
97 public int weight;
98 public Server(String ip, int weight) {
99 super();
100 this.ip = ip;
101 this.weight = weight;
102 }
103 public String getIp() {
104 return ip;
105 }
106 public void setIp(String ip) {
107 this.ip = ip;
108 }
109 public int getWeight() {
110 return weight;
111 }
112 public void setWeight(int weight) {
113 this.weight = weight;
114 }
115 }
116
117
118 public void init() {
119 Server s1 = new Server("192.168.0.100", 3);//3
120 Server s2 = new Server("192.168.0.101", 2);//2
121 Server s3 = new Server("192.168.0.102", 6);//6
122 Server s4 = new Server("192.168.0.103", 4);//4
123 Server s5 = new Server("192.168.0.104", 1);//1
124 serverList = new ArrayList<Server>();
125 serverList.add(s1);
126 serverList.add(s2);
127 serverList.add(s3);
128 serverList.add(s4);
129 serverList.add(s5);
130
131 currentIndex = -1;
132 currentWeight = 0;
133 serverCount = serverList.size();
134 maxWeight = getMaxWeightForServers(serverList);
135 gcdWeight = getGCDForServers(serverList);
136 }
137
138
139 public static void main(String[] args) {
140 WeightedRoundRobinScheduling obj = new WeightedRoundRobinScheduling();
141 obj.init();
142
143 Map<String,Integer> countResult = new HashMap<String,Integer>();
144
145 for (int i = 0; i < 100; i++) {
146 Server s = obj.GetServer();
147 String log = "ip:"+s.ip+";weight:"+s.weight;
148 if(countResult.containsKey(log)){
149 countResult.put(log,countResult.get(log)+1);
150 }else{
151 countResult.put(log,1);
152 }
153 System.out.println(log);
154 }
155
156 for(Entry<String, Integer> map : countResult.entrySet()){
157 System.out.println("服務器 "+map.getKey()+" 請求次數: "+map.getValue());
158 }
159 }
160
161 }
