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值得到離他最近的一個節點,如果沒有的話則取集合中第一個節點,這樣就形成了一個環。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章