1
训练营第五周作业
发布于: 2020 年 11 月 22 日
用你熟悉的编程语言实现一致性 hash 算法
public class ConsistencyShardingVirtualNodeDemo { /** 集群地址列表 */ private static String[] groups = { "192.168.0.0:8080", "192.168.0.1:8080", "192.168.0.2:8080", "192.168.0.3:8080"}; /** 虚拟节点映射关系 */ private static SortedMap<Integer, String> virtualNodes = new TreeMap<>(); private static final int VIRTUAL_NODE_NUM = 1000; static { // 将虚拟节点映射到Hash环上 for (int i = 0; i < groups.length; i++) { String group = groups[i]; for (int j = 0; j < VIRTUAL_NODE_NUM; j++) { String virtualNodeName = getVirtualNodeName(group, j); int hash = getHash(virtualNodeName); virtualNodes.put(hash, virtualNodeName); } } } private static String getVirtualNodeName(String realName, int num) { return realName + "&VN-" + String.valueOf(num); } private static String getRealNodeName(String virtualName) { return virtualName.split("&")[0]; } private static String getServer(String widgetKey) { int hash = getHash(widgetKey); // 只取出所有大于该hash值的部分而不必遍历整个Tree SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash); String virtualNodeName; if (subMap == null || subMap.isEmpty()) { // hash值在最尾部,应该映射到第一个group上 virtualNodeName = virtualNodes.get(virtualNodes.firstKey()); } else { virtualNodeName = subMap.get(subMap.firstKey()); } return getRealNodeName(virtualNodeName); } private static void randomTest() { Map<String, Integer> resMap = new HashMap<>(); for (int i = 0; i < 1000000; i++) { String server = getServer(UUID.randomUUID().toString()); if (resMap.containsKey(server)) { resMap.put(server, resMap.get(server) + 1); } else { resMap.put(server, 1); } } resMap.forEach((key, value) -> { System.out.println("server: " + key + " count: " + value + "(" + value / 10000.0D + "%)"); }); } public static int getHash(String str) { final int p = 16777619; int hash = (int) 2166136261L; for (int i = 0; i < str.length(); i++) { hash = (hash ^ str.charAt(i)) * p; } hash += hash << 13; hash ^= hash >> 7; hash += hash << 3; hash ^= hash >> 17; hash += hash << 5; if (hash < 0) { hash = Math.abs(hash); } return hash; } public static void main(String[] args) { randomTest(); }}复制代码
这个算法并没有第一次想出来,主要是卡在虚拟节点,不知道怎么加入。后来参考了一些网上的实现,发现是我想的复杂了。本质上,是对于 String 的 Hash,只要构造可以溯源的字符串就可以了(文中中的`$VN-`)。
另外,对于这个算法来说,`getHash`方法 是比较重要的一个点,如果算出来的 hash 不能均匀的分布在圆上,那么缓存也分布也不会均匀。
划线
评论
复制
发布于: 2020 年 11 月 22 日阅读数: 32
大脸猫
关注
还未添加个人签名 2018.04.27 加入
还未添加个人简介











评论 (1 条评论)