负载均衡
数据集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class ServerIps { public static List<String> ipList = new ArrayList<>(); static { ipList.add("192.168.0.1"); ipList.add("192.168.0.2"); ipList.add("192.168.0.3"); ipList.add("192.168.0.4"); ipList.add("192.168.0.5"); ipList.add("192.168.0.6"); ipList.add("192.168.0.7"); ipList.add("192.168.0.8"); ipList.add("192.168.0.9"); } public static Map<String, Integer> weightList = new HashMap<>(); static { weightList.put("192.168.0.1", 2); weightList.put("192.168.0.2", 8); weightList.put("192.168.0.3", 2); weightList.put("192.168.0.4", 3); weightList.put("192.168.0.5", 4); weightList.put("192.168.0.6", 6); weightList.put("192.168.0.7", 3); weightList.put("192.168.0.8", 5); weightList.put("192.168.0.9", 7); } }
|
1 2 3 4 5
| private static String getIp() { int pos = random.nextInt(ServerIps.ipList.size()); return ServerIps.ipList.get(pos); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
private static List<String> ips = new ArrayList<>(); static { for (String ip : ServerIps.weightList.keySet()) { Integer weightNum = ServerIps.weightList.get(ip); for (Integer i = 0; i < weightNum; i++) { ips.add(ip); } } }
private static Integer weightCount = 0; static { for (Integer integer : ServerIps.weightList.values()) { weightCount += integer; } System.out.println("weightCount = " + weightCount); } private static String getIps() { int r = random.nextInt(weightCount); System.out.print("r = " + r); for (String ip : ServerIps.weightList.keySet()) { Integer weight = ServerIps.weightList.get(ip); r = r - weight; if (r < 0) { return ip; } } return null; }
|
1 2 3 4 5 6
| private static Integer pos = 0; private static String getIp() { String ip = ServerIps.ipList.get(pos); pos = (pos + 1) % ServerIps.ipList.size(); return ip; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
private static List<String> ipList = new ArrayList<>(); static { for (String ip : ServerIps.weightList.keySet()) { Integer weight = ServerIps.weightList.get(ip); for (Integer num = 0; num < weight; num++) { ipList.add(ip); } } } private static Integer pos = 0; private static String getIp() { String ip = ipList.get(pos); pos = (pos + 1) % ipList.size(); return ip; }
private static Integer weightCount = 0; static { for (Integer integer : ServerIps.weightList.values()) { weightCount += integer; } System.out.println("weightCount = " + weightCount); } private static String getIps() { int r = pos; for (String ip : ServerIps.weightList.keySet()) { Integer weight = ServerIps.weightList.get(ip); r = r - weight; if (r < 0) { pos = (pos + 1) % weightCount; return ip; } } return null; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
private static Map<String, Weight> weightMap = new HashMap<>();
private static Integer totalWeight;
static { weightMap.put("A", new Weight(5, "A", 5)); weightMap.put("B", new Weight(1, "B", 1)); weightMap.put("C", new Weight(1, "C", 1)); totalWeight = weightMap.values().stream().map(Weight::getW).reduce(0, (w1, w2) -> w1 + w2); }
private static String getIp() { Weight maxWeight = null; for (Weight weight : weightMap.values()) { if (maxWeight == null || weight.getCw() > maxWeight.getCw()) { maxWeight = weight; } } maxWeight.setCw(maxWeight.getCw() - totalWeight); for (Weight weight : weightMap.values()) { weight.setCw(weight.getCw() + weight.getW()); } return maxWeight.getIp(); }
|
构造一个长度为232的整数环(一致性Hash环),然后根据节点名称的Hash值(分布在0 - 232-1)将服务器节点放置在这个Hash环上。最后,根据数据的Key值计算得到其Hash值,在Hash环上顺时针查找距离这个Key值的Hash值最近的服务器节点,完成Key到服务器的映射查找。
在服务器较少的情况下,会造成分布不均匀,引入 “虚拟节点” 用于解决数据倾斜问题。

每个Invoker会共创建160个虚拟节点,Hash环总长度为160*节点数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private static TreeMap<Integer, String> virtualInvokers = new TreeMap<>();
private static int replicaNumber = 160; static { for (String ip : ServerIps.ipList) { for (int i = 0; i < replicaNumber; i++) { int hash = getHash(ip + "VN" + i); virtualInvokers.put(hash, ip); } } }
private String selectForKey(int hash) { Map.Entry<Integer, String> entry = virtualInvokers.tailMap(hash, true).firstEntry(); if (entry == null) { entry = virtualInvokers.firstEntry(); } return entry.getValue(); }
|
活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求,此时应优先将请求分配给该服务提供者。
Dubbo会为每个服务提供者Invoker分配一个active,代表活跃数大小。调用之前做自增操作,调用完成后做自减操作。这样有的服务处理的快,有的处理的慢。越快的,active数量越小,就优先分配。