一致性hash算法

算法原理分析

请参考:https://www.cnblogs.com/lpfuture/p/5796398.html

源码示例



import org.apache.commons.lang3.StringUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

public class ConsistentHashing {

    //待添加入Hash环的服务器列表
    private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111",
            "192.168.0.3:111", "192.168.0.4:111", "192.168.0.5:111"};

    //真实节点列表
    private static List<String> realNodes = new LinkedList<>();

    //虚拟节点列表
    private static SortedMap<Integer, String> sortedMap = new TreeMap<>();

    // 真实节点对应的虚拟节点数
    private static final int NUM_HOST = 5;

    //程序初始化,将所有的服务器放入sortedMap中
    static {
        //添加真实节点
        for (int i = 0; i < servers.length; i++) {
            realNodes.add(servers[i]);
        }
        //添加虚拟节点
        for (String str : realNodes) {
            for (int i = 1; i <= NUM_HOST; i++) {
                String nodeName = str + "VM" + String.valueOf(i);
                int hash = getHash(nodeName);
                sortedMap.put(hash, nodeName);
                System.out.println("虚拟节点hash:" + hash + "【" + nodeName + "】放入");
            }
        }
    }

    //得到应当路由到的结点
    private static String getServer(String key) {
        //得到该key的hash值
        int hash = getHash(key);
        //得到大于该Hash值的所有Map
        String host;
        SortedMap<Integer, String> subMap = sortedMap.tailMap(hash);
        if (subMap.isEmpty()) {
            //如果没有比该key的hash值大的,则从第一个node开始
            Integer i = sortedMap.firstKey();
            //返回对应的服务器
            host = sortedMap.get(i);
        } else {
            //第一个Key就是顺时针过去离node最近的那个结点
            Integer i = subMap.firstKey();
            //返回对应的服务器
            host = subMap.get(i);
        }
        if (StringUtils.isNotBlank(host)) {
            String realHost = host.substring(0, host.indexOf("VM"));
            return realHost;
        }
        return null;
    }

    //使用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;
    }

    // 测试
    public static void main(String[] args) {
        String[] keys = {"1", "2","5", "6", "14","15"};
        for (int i = 0; i < keys.length; i++) {
            System.out.println("[" + keys[i] + "]的hash值为" +
                    getHash(keys[i]) + ", 被路由到结点[" + getServer(keys[i]) + "]");
        }
    }

}



测试输出结果

虚拟节点hash:203600595【192.168.0.0:111VM1】放入
虚拟节点hash:533864743【192.168.0.0:111VM2】放入
虚拟节点hash:283014282【192.168.0.0:111VM3】放入
虚拟节点hash:112805468【192.168.0.0:111VM4】放入
虚拟节点hash:2047670539【192.168.0.0:111VM5】放入

虚拟节点hash:519865065【192.168.0.1:111VM1】放入
虚拟节点hash:1154856732【192.168.0.1:111VM2】放入
虚拟节点hash:1253620420【192.168.0.1:111VM3】放入
虚拟节点hash:271923136【192.168.0.1:111VM4】放入
虚拟节点hash:954403340【192.168.0.1:111VM5】放入

虚拟节点hash:1573046012【192.168.0.2:111VM1】放入
虚拟节点hash:1216691265【192.168.0.2:111VM2】放入
虚拟节点hash:1427550122【192.168.0.2:111VM3】放入
虚拟节点hash:563194059【192.168.0.2:111VM4】放入
虚拟节点hash:1191243314【192.168.0.2:111VM5】放入

虚拟节点hash:449809950【192.168.0.3:111VM1】放入
虚拟节点hash:1517398358【192.168.0.3:111VM2】放入
虚拟节点hash:1061446677【192.168.0.3:111VM3】放入
虚拟节点hash:1711703068【192.168.0.3:111VM4】放入
虚拟节点hash:888576886【192.168.0.3:111VM5】放入

虚拟节点hash:300861392【192.168.0.4:111VM1】放入
虚拟节点hash:185778140【192.168.0.4:111VM2】放入
虚拟节点hash:70846991【192.168.0.4:111VM3】放入
虚拟节点hash:20072546【192.168.0.4:111VM4】放入
虚拟节点hash:294895133【192.168.0.4:111VM5】放入

虚拟节点hash:1533857590【192.168.0.5:111VM1】放入
虚拟节点hash:1043993658【192.168.0.5:111VM2】放入
虚拟节点hash:1031128652【192.168.0.5:111VM3】放入
虚拟节点hash:1197352122【192.168.0.5:111VM4】放入
虚拟节点hash:662112606【192.168.0.5:111VM5】放入

[1]的hash值为1081142246, 被路由到结点[192.168.0.1:111]
[2]的hash值为1310673766, 被路由到结点[192.168.0.2:111]
[5]的hash值为1039214538, 被路由到结点[192.168.0.5:111]
[6]的hash值为853429834, 被路由到结点[192.168.0.3:111]
[14]的hash值为2038748830, 被路由到结点[192.168.0.0:111]
[15]的hash值为2102931218, 被路由到结点[192.168.0.4:111]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值