Java代码实现一致性Hash算法(这可能是java中最简单的一致性Hash算法实现方式)

缘起

关于一致性hash算法的原理,本文不做概述。本文说的是如何在java中实现一致性Hash算法。

代码

package com.bxoon.test;

import java.util.*;

/**
 * 一致性Hash
 * @author zhongguangxi
 */
public class ConsistenceHash {

    // 物理节点集合
    private List<String> realNodes = new ArrayList<>();
    // 虚拟节点数,用户指定
    private int viretalNums = 100;
    // 物理节点与虚拟节点的对应关系存储
    private Map<String,List<Integer>> real2VirtualMap = new HashMap<>();
    // 排序存储结构红黑树,key是虚拟节点的hash值,value是物理节点
    private SortedMap<Long,String> sortedMap = new TreeMap<>();

    public ConsistenceHash(int viretalNums) {
        super();
        this.viretalNums = viretalNums;
    }

    public ConsistenceHash() {
        super();
    }

    /**
     * 添加物理节点
     * @param node
     */
    public void addService(String node){
        String vnode = null;
        int i = 0;
        for (int count=0;count<viretalNums;){
            i++;
            vnode = node+"-"+i;
            long hashValue = FNV1_32_HASH.hash(vnode);
            if (!this.sortedMap.containsKey(hashValue)){
                count++;
                this.sortedMap.put(hashValue,node);
            }
        }
        this.realNodes.add(node);
    }

    /**
     * 删除物理节点
     * @param node
     */
    public void removeService(String node){

    }

    /**
     * 获取数据的存取节点
     * @param key
     * @return
     */
    public String getService(String key){
        long hash = FNV1_32_HASH.hash(key);
        SortedMap<Long,String> map = this.sortedMap.tailMap(hash);
        if (map.isEmpty()){
            return this.sortedMap.get(sortedMap.firstKey());
        }else{
            return map.get(map.firstKey());
        }
    }


    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        ConsistenceHash consistenceHash = new ConsistenceHash();
        consistenceHash.addService("193.168.1.10");
        consistenceHash.addService("193.168.1.11");
        consistenceHash.addService("193.168.1.12");
        for (int i =0;i<100;i++){
            System.out.println("a"+i+" 对应的服务器:"+consistenceHash.getService("a"+i));
        }
    }


}

输出结果

a0 对应的服务器:193.168.1.12
a1 对应的服务器:193.168.1.12
a2 对应的服务器:193.168.1.12
a3 对应的服务器:193.168.1.11
a4 对应的服务器:193.168.1.10
a5 对应的服务器:193.168.1.11
a6 对应的服务器:193.168.1.10
a7 对应的服务器:193.168.1.12
a8 对应的服务器:193.168.1.10
a9 对应的服务器:193.168.1.11
a10 对应的服务器:193.168.1.12
a11 对应的服务器:193.168.1.12
a12 对应的服务器:193.168.1.12
a13 对应的服务器:193.168.1.12
a14 对应的服务器:193.168.1.11
a15 对应的服务器:193.168.1.10
a16 对应的服务器:193.168.1.10
a17 对应的服务器:193.168.1.10
a18 对应的服务器:193.168.1.10
a19 对应的服务器:193.168.1.10
a20 对应的服务器:193.168.1.12
a21 对应的服务器:193.168.1.12
a22 对应的服务器:193.168.1.10
a23 对应的服务器:193.168.1.10
a24 对应的服务器:193.168.1.12
a25 对应的服务器:193.168.1.10
a26 对应的服务器:193.168.1.12
a27 对应的服务器:193.168.1.11
a28 对应的服务器:193.168.1.10
a29 对应的服务器:193.168.1.12
a30 对应的服务器:193.168.1.12
a31 对应的服务器:193.168.1.12
a32 对应的服务器:193.168.1.12
a33 对应的服务器:193.168.1.12
a34 对应的服务器:193.168.1.12
a35 对应的服务器:193.168.1.10
a36 对应的服务器:193.168.1.10
a37 对应的服务器:193.168.1.11
a38 对应的服务器:193.168.1.10
a39 对应的服务器:193.168.1.11
a40 对应的服务器:193.168.1.11
a41 对应的服务器:193.168.1.11
a42 对应的服务器:193.168.1.12
a43 对应的服务器:193.168.1.10
a44 对应的服务器:193.168.1.12
a45 对应的服务器:193.168.1.11
a46 对应的服务器:193.168.1.10
a47 对应的服务器:193.168.1.11
a48 对应的服务器:193.168.1.10
a49 对应的服务器:193.168.1.10
a50 对应的服务器:193.168.1.10
a51 对应的服务器:193.168.1.10
a52 对应的服务器:193.168.1.12
a53 对应的服务器:193.168.1.10
a54 对应的服务器:193.168.1.10
a55 对应的服务器:193.168.1.11
a56 对应的服务器:193.168.1.10
a57 对应的服务器:193.168.1.11
a58 对应的服务器:193.168.1.12
a59 对应的服务器:193.168.1.12
a60 对应的服务器:193.168.1.12
a61 对应的服务器:193.168.1.11
a62 对应的服务器:193.168.1.12
a63 对应的服务器:193.168.1.10
a64 对应的服务器:193.168.1.12
a65 对应的服务器:193.168.1.12
a66 对应的服务器:193.168.1.11
a67 对应的服务器:193.168.1.10
a68 对应的服务器:193.168.1.12
a69 对应的服务器:193.168.1.12
a70 对应的服务器:193.168.1.11
a71 对应的服务器:193.168.1.12
a72 对应的服务器:193.168.1.12
a73 对应的服务器:193.168.1.10
a74 对应的服务器:193.168.1.12
a75 对应的服务器:193.168.1.10
a76 对应的服务器:193.168.1.12
a77 对应的服务器:193.168.1.10
a78 对应的服务器:193.168.1.10
a79 对应的服务器:193.168.1.11
a80 对应的服务器:193.168.1.12
a81 对应的服务器:193.168.1.10
a82 对应的服务器:193.168.1.12
a83 对应的服务器:193.168.1.12
a84 对应的服务器:193.168.1.12
a85 对应的服务器:193.168.1.12
a86 对应的服务器:193.168.1.10
a87 对应的服务器:193.168.1.10
a88 对应的服务器:193.168.1.11
a89 对应的服务器:193.168.1.10
a90 对应的服务器:193.168.1.11
a91 对应的服务器:193.168.1.12
a92 对应的服务器:193.168.1.11
a93 对应的服务器:193.168.1.12
a94 对应的服务器:193.168.1.10
a95 对应的服务器:193.168.1.11
a96 对应的服务器:193.168.1.11
a97 对应的服务器:193.168.1.10
a98 对应的服务器:193.168.1.10
a99 对应的服务器:193.168.1.11

结论

可以看到测试结果,每一个key都落在了对应的节点上。

基本原理

1.添加物理节点的时候要添加对应的虚拟节点
2.在一个Map<String,Node>中保存虚拟节点和物理节点的对应关系,其中key为虚拟节点的Hash,而value为物理节点
3.在获取节点的时候,根据某个key的hash值得到离他最近的一个节点,如果没有的话则取集合中第一个节点,这样就形成了一个环。

发布了114 篇原创文章 · 获赞 146 · 访问量 35万+

猜你喜欢

转载自blog.csdn.net/qq32933432/article/details/94965882