世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。
意图:服务器负载均衡,使请求分配的更均匀,并且提高服务器的可伸缩性示意图: 过程 过程:为每个服务器创建多个虚拟节点(分布越均匀越好)取hash值形成hash环,请求过来时,请求key的hash值放入到环中做判断,找到顺时针最近的虚拟节点,这个节点所对应的服务器即为所要请求的服务器。 当添加或删除服务器时,只会影响附近的节点,不会对整体的均匀性造成太大的冲击。 并且服务器越多,请求的均匀性分配的越好。实例 public class ConsistentHash { private static TreeMap<Long, String> treeMap = new TreeMap<>(); public static void main(String[] args) { String ipPre = "192.168.2."; // 为每个服务添加虚拟节点,hash环 for (int i = 0; i < 10; i ++) { put(100, ipPre + i); } // 随机请求,统计个服务接收到的请求次数 Map<String, Integer> countMap = new HashMap<>(); for (int i = 0; i < 10000; i ++) { String ip = get(hash(UUID.randomUUID().toString()+i)); countMap.compute(ip, (a, b) -> { if (null == b) return 1; return b + 1; }); } countMap.forEach((a, b) -> { System.out.println("ip = " + a + ", count = " + b); }); } public static void put (int n, String ip) { for (int i = 0; i < n; i ++) { treeMap.put(hash((ip+i)), ip); } } public static void remove (int n, String ip) { for (int i = 0; i < n; i++) { treeMap.remove(hash.hash((ip+i))); } } public static String get (Long key) { if (treeMap.containsKey(key)) return treeMap.get(key); SortedMap<Long, String> tailMap = treeMap.tailMap(key); key = tailMap.isEmpty() ? treeMap.firstKey() : tailMap.firstKey(); return treeMap.get(key); } public static Long hash(String key) { ByteBuffer buf = ByteBuffer.wrap(key.getBytes()); int seed = 0x1234ABCD; ByteOrder byteOrder = buf.order(); buf.order(ByteOrder.LITTLE_ENDIAN); long m = 0xc6a4a7935bd1e995L; int r = 47; long h = seed ^ (buf.remaining() * m); long k; while (buf.remaining() >= 8) { k = buf.getLong(); k *= m; k ^= k >>> r; k *= m; h ^= k; h *= m; } if (buf.remaining() > 0) { ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); finish.put(buf).rewind(); h ^= finish.getLong(); h *= m; } h ^= h >>> r; h *= m; h ^= h >>> r; buf.order(byteOrder); return h; } }运行结果:
ip = 192.168.2.0, count = 1110 ip = 192.168.2.2, count = 1044 ip = 192.168.2.1, count = 1119 ip = 192.168.2.8, count = 1074 ip = 192.168.2.7, count = 859 ip = 192.168.2.9, count = 1033 ip = 192.168.2.4, count = 1075 ip = 192.168.2.3, count = 878 ip = 192.168.2.6, count = 890 ip = 192.168.2.5, count = 918