Week 5 命题作业
发布于: 2020 年 11 月 06 日
实现思路:
- 使用支持排序的 TreeMap 实现 Hash 环 
- 使用 Java 原生的 Object.hashCode 获取 hashCode 
- 每台服务器使用 50 个节点,三台服务器共 150 个节点(经验值?) 
public class ConsistentHashUtils {    /**     * 服务器节点,应该从配置文件中取读     */    private static String[] servers = {"192.12.43.222", "44.36.14.25", "45.26.48.91"};    /**     * 使用排序集合 TreeMap 实现 Hash 环     */    private static SortedMap<Long, String> hashRing = new TreeMap<>();    /**     * 生成 Hash 环,并安放服务器节点及其虚拟节点。     * <p>     * 1. 当服务器节点发生改变(增删改)时,需要重新生成     * 2. 服务器节点不变时,Hash 环也不能变,否则可能一个 key 每次分配到的服务器不一样     * 3. 这个方法应该是在程序启动时执行,且在服务器节点发生改变时,由专门的后台线程执行!     */    public static void generateHashRing() {        for (String server : servers) {            // 把服务器及对应虚拟节点保存到 treeMap 中,也就是放到 hash 环上            // 这里每个服务器写死 49 个虚拟节点            for (int i = 0; i < 50; i++) {                // 加上一个随机值,保证所有虚拟节点计算的 hash 值不同                long hashCode = getHashCode(server + UUID.randomUUID());                // 上环                hashRing.put(hashCode, server);            }        }    }    /**     * 获取一致性 Hash 算法分配到的服务器节点     *     * treeMap 按自然数从小到大排序,要找出第一个比 dataKey HashCode 大的服务器节点,也就是顺时针第一个,     * 直接将 treeMap 从 dataKey HashCode 截断即可,然后有两种情况     * 1. 没有比它大的,则取整个 treeMap 的第一条数据     * 2. 否则,取截断后的第一条数据     *     * @param dataKey key     * @return 服务器节点     */    public static String getServerByConsistentHash(String dataKey) {        String server;        SortedMap<Long, String> tailMap = hashRing.tailMap(getHashCode(dataKey));        if (tailMap.isEmpty()) {            server = hashRing.get(hashRing.firstKey());        } else {            server = hashRing.get(tailMap.firstKey());        }        return server;    }    /**     * 获取字符串对应的 hashCode     *     * @param str 需要计算 Hash 的字符串     * @return hashCode     */    private static long getHashCode(String str) {        return Math.abs(str.hashCode()) << 2;    }    /**     * 测试     */    public static void main(String[] args) {        // 使用 Map 记录测试结果        Map<String, Integer> resultMap = new HashMap<>();        for (String server : servers) {            resultMap.put(server, 0);        }        // 生成 Hash 环        generateHashRing();        // 测试 10 万条数据        for (int i = 0; i < 100000; i++) {            String key = UUID.randomUUID().toString();            String server = getServerByConsistentHash(key);            resultMap.put(server, resultMap.get(server) + 1);        }        resultMap.forEach((key, value) -> System.out.println(String.format("服务器 %s,分配到的数量:%d", key, value)));    }}测试结果:
服务器 44.36.14.25,分配到的数量:30640服务器 45.26.48.91,分配到的数量:35955服务器 192.12.43.222,分配到的数量:33405
划线
评论
复制
发布于: 2020 年 11 月 06 日阅读数: 21
balsamspear
关注
还未添加个人签名 2019.10.24 加入
还未添加个人简介











 
    
评论