zllbirdonland 2020-02-10
主要思想是服务器一个接一个的服务
public class RoundRobin { private static Integer pos = 0; public static String getServer() { if(pos >= ServerIps.LIST.size()) { pos = 0; } String ip = ServerIps.LIST.get(pos); pos++; return ip; } public static void main(String[] args) { for(int i = 0; i < 20; i++) { System.out.println(getServer()); } } }
考虑权重的时候
其中A、B、C分别代表3个IP地址,权重分别为5、3、2 A: 5 B: 3 C: 2
映射到坐标轴为
0-----5---8--10
offset的取值再不是一个随机数,而是0,1,2,3,4,5,6,7,8,9
1 ——> A
2 ——> A
...
6 ——> B
...
代码实现
import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class ServerIps { public static final Map<String, Integer> WEIGHT_MAP = new LinkedHashMap<>(); static { WEIGHT_MAP.put("192.168.0.1", 2); WEIGHT_MAP.put("192.168.0.2", 8); WEIGHT_MAP.put("192.168.0.3", 1); WEIGHT_MAP.put("192.168.0.4", 9); WEIGHT_MAP.put("192.168.0.5", 4); WEIGHT_MAP.put("192.168.0.6", 6); } }
注意其中采用的是LinkedHashMap,这样可以保证输出的顺序和输入的顺序一致
public class RequestId { public static Integer num = 0; public static Integer getAndIncrement() { return num++; } }
上面代码模仿的是客户的ID号,根据客户的ID号来控制服务器的轮询。
public class RoundRobin2 { public static String getServer() { int totalWeight = 0; for (Integer weight: ServerIps.WEIGHT_MAP.values()) { totalWeight += weight; } int requestId = RequestId.getAndIncrement(); int offset = requestId % totalWeight; for(String ip: ServerIps.WEIGHT_MAP.keySet()) { Integer weight = ServerIps.WEIGHT_MAP.get(ip); if (offset < weight) { return ip; } offset -= weight; } return null; } public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.println(getServer()); } } }
Nginx默认采用这种算法
A: 5
B: 1
C: 1
这样的话,优化1中的访问顺序为AAAAABC,这样的话对服务器A的压力比较大
如果按照离散的话,就不会有这样的问题,如下面这种顺序
AABACAA
这样不仅能使服务比较分散,也能保证权重,还能达到轮询的目的
具体过程如下:
ip
weight: 静态,5,1,1 currentWeight:动态
currentWeight: 0,0,0
currentWeight+=weight | max(currentWeight) | result | max(currentWeight)-=sum(weight)7 |
---|---|---|---|
5,1,1 | 5 | A | -2,1,1 |
3,2,2 | 3 | A | -4,2,2 |
1,3,3 | 3 | B | 1,-4,3 |
6,-3,4 | 6 | A | -1,-3,4 |
4,-2,5 | 5 | C | 4,-2,-2 |
9,-1,-1 | 9 | A | 2,-1,-1 |
7,0,0 | 7 | A | 0,0,0 |
5,1,1 | ... | ... | ... |
代码实现
public class Weight { private String ip; private Integer weight; private Integer currentWeight; public Weight(String ip, Integer weight, Integer currentWeight) { super(); this.ip = ip; this.weight = weight; this.currentWeight = currentWeight; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public Integer getCurrentWeight() { return currentWeight; } public void setCurrentWeight(Integer currentWeight) { this.currentWeight = currentWeight; } }
=============================
import java.util.LinkedHashMap; import java.util.Map; public class WeightRoundRobin { private static Map<String, Weight> weightMap = new LinkedHashMap<>(); public static String getServer() { if(weightMap.isEmpty()) { for(String ip: ServerIps.WEIGHT_MAP.keySet()) { Integer weight = ServerIps.WEIGHT_MAP.get(ip); weightMap.put(ip, new Weight(ip, weight, 0)); } } // currentWeight += weight for(Weight weight: weightMap.values()) { weight.setCurrentWeight(weight.getCurrentWeight() + weight.getWeight()); } Weight maxCurrentWeight = null; for (Weight weight: weightMap.values()) { if (maxCurrentWeight == null || weight.getCurrentWeight() > maxCurrentWeight.getCurrentWeight()) { maxCurrentWeight = weight; } } // max(currentWeight) -= sum(weight) int totalWeight = 0; for (Integer weight: ServerIps.WEIGHT_MAP.values()) { totalWeight += weight; } maxCurrentWeight.setCurrentWeight(maxCurrentWeight.getCurrentWeight() - totalWeight); //result return maxCurrentWeight.getIp(); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.println(getServer()); } } }