import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import java.util.*; /** * 一致性hash */ public class ConsistentHashWithVirtualNode { /** * 待添加入Hash环的服务器列表 */ private static String[] SERVERS = {"192.168.1.2:6379", "192.168.1.3:6379"}; /** * key表示服务器的hash值,value表示虚拟节点的名称 */ private static SortedMap<Integer, String> HASH_CIRCLE = new TreeMap<Integer, String>(); /** * 用于结果统计 */ private static Map<String, Integer> result = new HashMap<String, Integer>(); /** * 每个真实节点对应虚拟节点数 */ private static Integer VIRTUAL_NODES_NUM = 150; /** * 使用FNV1_32_HASH算法计算服务器的Hash值 */ private 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; } static { for (int i = 0; i < SERVERS.length; i++) { for (Integer j = 0; j < VIRTUAL_NODES_NUM; j++) { setServer(SERVERS[i] + "vn" + j); } } } private static void setServer(String ip) { setServer(ip, null); } private static void setServer(String ip, Integer hash) { hash = hash != null ? getHash(hash.toString()) : getHash(ip); if (StringUtils.isBlank(HASH_CIRCLE.get(hash))) { HASH_CIRCLE.put(hash, ip); System.out.println("[" + ip + "]加入sortedMap中, 其Hash值为" + hash); } else { //解决hash碰撞 setServer(ip, hash); } } public static void main(String[] args) { for (int i = 0; i < 50; i++) { long nodes = RandomUtils.nextLong(); String server = getServer(nodes); String realServer = server.split("vn")[0]; System.out.println("[" + nodes + "]的hash值为" + getHash("" + nodes) + ", 被路由到虚拟结点[" + server + "], 真实结点[" + realServer + "]"); result.put(realServer, (result.get(realServer) == null ? 0 : result.get(realServer)) + 1); } result.forEach((k, v) -> { System.out.println("结点[" + k + "]上有" + v); }); } public static String getServer(Object node) { String ip = HASH_CIRCLE.get(HASH_CIRCLE.firstKey()); // 得到带路由的结点的Hash值 int hash = getHash(node.toString()); // 得到大于该Hash值的所有Map SortedMap<Integer, String> subMap = HASH_CIRCLE.tailMap(hash); if (!subMap.isEmpty()) { // 第一个Key就是顺时针过去离node最近的那个结点 Integer i = subMap.firstKey(); ip = subMap.get(i); } // 返回对应的服务器名称 return ip; } }
java实现hash一致性算法
猜你喜欢
转载自www.cnblogs.com/bootdo/p/10437683.html
今日推荐
周排行