在多台機器實現負載均衡的時候,經常用到輪詢調度算法(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 }