在多台机器实现负载均衡的时候,经常用到轮询调度算法(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 }