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