欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)一致性Hash算法詳情

 更新時間:2022年09月07日 11:26:21   作者:何憶清風(fēng)  
這篇文章主要介紹了Java實現(xiàn)一致性Hash算法詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

1. 實現(xiàn)原理

將key映射到 2^32 - 1 的空間中,將這個數(shù)字的首尾相連,形成一個環(huán)

  • 計算節(jié)點(使用節(jié)點名稱、編號、IP地址)的hash值,放置在環(huán)上
  • 計算key的hash值,放置在環(huán)上,順時針尋找到的第一個節(jié)點,就是應(yīng)選取的節(jié)點

例如:p2、p4、p6三個節(jié)點,key11、key2、key27按照順序映射到p2、p4、p6上面,假設(shè)新增一個節(jié)點p8在p6節(jié)點之后,這個時候只需要將key27從p6調(diào)整到p8就可以了;也就是說,每次新增刪除節(jié)點時,只需要重新定位該節(jié)點附近的一小部分?jǐn)?shù)據(jù)

2. 解決數(shù)據(jù)傾斜的問題

2.1 什么是數(shù)據(jù)傾斜?

如果服務(wù)器的節(jié)點過少,容易引起key的傾斜。例如上面的例子中p2、p4、p6分布在環(huán)的上半部分,下半部分是空的。那么映射到下半部分的key都會被分配給p2,key過度傾斜到了p2緩存間節(jié)點負(fù)載不均衡。

2.2 解決

為了解決這個問題,引入了虛擬節(jié)點的概念,一個真實的節(jié)點對應(yīng)多個虛擬的節(jié)點,假設(shè)1個真實的節(jié)點對應(yīng)3個虛擬節(jié)點,那么p1對應(yīng)的就是p1-1、p1-2、p1-3

  • 計算虛擬節(jié)點的Hash值,放置在環(huán)上
  • 計算key的Hash值,在環(huán)上順時針尋找到對應(yīng)選取的虛擬節(jié)點,例如:p2-1,對應(yīng)真實的節(jié)點p2

虛擬節(jié)點擴充了節(jié)點的數(shù)量,解決了節(jié)點較少的情況下數(shù)據(jù)傾斜的問題,而且代價非常小,只需要新增一個字典(Map)維護真實的節(jié)點與虛擬節(jié)點的映射關(guān)系就可以了

3. 代碼實現(xiàn)

3.1 ConsistentHash

這里使用了泛型的方式來保存數(shù)據(jù),可以根據(jù)不同的類型,獲取到不同的節(jié)點存儲

public class ConsistentHash<T> {

    //自定義hash方法
    private Hash<Object> hashMethod;

    //創(chuàng)建hash映射,虛擬節(jié)點映射真實節(jié)點
    private final Map<Integer, T> hashMap = new ConcurrentHashMap<>();

    //將所有的hash保存起來
    private List<Integer> keys = new ArrayList<>();

    //默認(rèn)虛擬節(jié)點數(shù)量
    private final int replicas;

    public ConsistentHash() {
        this(3, Utils::rehash);
    }

    public ConsistentHash(int replicas, Hash<Object> hashMethod) {
        this.replicas = replicas;
        this.hashMethod = hashMethod;
    }

    @SafeVarargs
    public final void add(T... keys) {
        for (T key : keys) {
            //根據(jù)虛擬節(jié)點個數(shù)來計算虛擬節(jié)點
            for (int i = 0; i < this.replicas; i++) {
                //根據(jù)函數(shù)獲取到對應(yīng)的hash值
                int hash = this.hashMethod.hash(i + ":" + key.toString());
                this.keys.add(hash);
                this.hashMap.put(hash, key);
            }
        }
        //排序,因為是一個環(huán)狀結(jié)構(gòu)
        Collections.sort(this.keys);
    }

    /**
     * 根據(jù)對應(yīng)的key來獲取到節(jié)點信息
     *
     * @param key
     * @return
     */
    public T get(Object key) {
        Objects.requireNonNull(key, "key不能為空");
        int hash = this.hashMethod.hash(key);
        //獲取到對應(yīng)的節(jié)點信息
        int idx = Utils.search(this.keys.size(), h -> this.keys.get(h) >= hash);
        //如果idx == this.keys.size() ,就代表需要取 this.keys.get(0); 因為是環(huán)狀,所以需要使用 % 來進行處理
        return this.hashMap.get(this.keys.get(idx % this.keys.size()));
    }
}

3.2 Hash

這里定義了一個函數(shù)結(jié)構(gòu),用于自定計算hash值

@FunctionalInterface
public static interface Hash<T> {
    /**
     * 計算hash值
     *
     * @param t
     * @return int類型
     */
    int hash(T t);
}

3.3 Utils

由于hashcode采用的int類型進行存儲,那么就需要考慮,hash是否超過了int最大存儲,如果超過了那么存儲的數(shù)字就是負(fù)數(shù),會對獲取節(jié)點造成影響,所以這里在取hash值時,采用了hashmap中獲取到hashcode之后對其進行與操作,可以減少hash沖突,也可以避免負(fù)數(shù)的產(chǎn)生

public static class Utils {
		// int類型的最大數(shù)據(jù)
        static final int HASH_BITS = 0x7fffffff;

        /**
         * 通過二分查找法,定義數(shù)組索引位置
         *
         * @param len
         * @param f
         * @return
         */
        public static int search(int len, Function<Integer, Boolean> f) {
            int i = 0, j = len;
            //通過二分查找發(fā)來定為索引位置
            while (i < j) {
                //長度除于2
                int h = (i + j) >> 1;
                //調(diào)用函數(shù),判斷當(dāng)前的索引值是否大于
                if (f.apply(h)) {
                    //向低半段進行遍歷
                    j = h;
                } else {
                    //向高半段進行遍歷
                    i = h + 1;
                }
            }
            return i;
        }
        /**
         * 將返回的hash能夠平均的計算在 int類型之間
         *
         * @param o
         * @return
         */
        public static int rehash(Object o) {
            int h = o.hashCode();
            return (h ^ (h >>> 16)) & HASH_BITS;
        }
    }

3.4 main

下面是main方法進行測試,在后面新增了一個節(jié)點之后,只會調(diào)整 zs 數(shù)據(jù)到 109 節(jié)點,而且其他兩個key的獲取不會受到影響

public static void main(String[] args) {
        ConsistentHash<String> consistentHash = new ConsistentHash<>();
        consistentHash.add("192.168.2.106", "192.168.2.107", "192.168.2.108");

        Map<String, Object> map = new HashMap<>();
        map.put("zs", "192.168.2.108");
        map.put("999999", "192.168.2.106");
        map.put("233333", "192.168.2.106");

        map.forEach((k, v) -> {
            String node = consistentHash.get(k);
            if (!v.equals(node)) {
                throw new IllegalArgumentException("節(jié)點獲取錯誤,key:" + k + ",獲取到的節(jié)點值為:" + node);
            }
        });

        consistentHash.add("192.168.2.109");
        map.put("zs", "192.168.2.109");
        map.forEach((k, v) -> {
            String node = consistentHash.get(k);
            if (!v.equals(node)) {
                throw new IllegalArgumentException("節(jié)點獲取錯誤,key:" + k + ",獲取到的節(jié)點值為:" + node);
            }
        });
    }

到此這篇關(guān)于Java實現(xiàn)一致性Hash算法詳情的文章就介紹到這了,更多相關(guān)Java Hash算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud注冊中心之consul詳細(xì)講解使用方法

    SpringCloud注冊中心之consul詳細(xì)講解使用方法

    Consul是一款由HashiCorp公司開源的,用于服務(wù)治理的軟件,Spring Cloud Consul對其進行了封裝,這篇文章主要介紹了springcloud組件consul服務(wù)治理,需要的朋友可以參考下
    2022-11-11
  • VMware虛擬機下hadoop1.x的安裝方法

    VMware虛擬機下hadoop1.x的安裝方法

    這篇文章主要為大家詳細(xì)介紹了VMware虛擬機下hadoop1.x的安裝方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • WebSocket實現(xiàn)聊天室業(yè)務(wù)

    WebSocket實現(xiàn)聊天室業(yè)務(wù)

    這篇文章主要為大家詳細(xì)介紹了WebSocket實現(xiàn)聊天室業(yè)務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • java.lang.String類的使用

    java.lang.String類的使用

    這篇文章主要介紹了java.lang.String類的使用,以及字符串的相關(guān)知識,需要了解相關(guān)知識的小伙伴可以參考該篇文章
    2021-08-08
  • Java編程代碼性能優(yōu)化

    Java編程代碼性能優(yōu)化

    本文介紹了 Java 代碼優(yōu)化的過程,總結(jié)了優(yōu)化 Java 程序的一些最佳實踐,分析了進行優(yōu)化的方法,并解釋了性能提升的原因,需要的朋友可以參考下
    2015-11-11
  • java使用Validation進行數(shù)據(jù)校驗的方式總結(jié)

    java使用Validation進行數(shù)據(jù)校驗的方式總結(jié)

    在Java中提供了一系列的校驗方式,下面這篇文章主要給大家介紹了關(guān)于java使用Validation進行數(shù)據(jù)校驗的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • springmvc整合ssm配置的詳細(xì)代碼

    springmvc整合ssm配置的詳細(xì)代碼

    今天通過實例代碼給大家介紹了springmvc整合ssm配置的詳細(xì)方法,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-11-11
  • Idea?springboot?springCloud熱加載熱調(diào)試兩種常用方式

    Idea?springboot?springCloud熱加載熱調(diào)試兩種常用方式

    這篇文章主要介紹了Idea?springboot?springCloud熱加載熱調(diào)試常用的兩種方式,在項目開發(fā)的過程中,需要修改調(diào)試的時候偶每次都需要重啟項目浪費時間,下面是我整理的兩種常用的兩種方式,需要的朋友可以參考下
    2023-04-04
  • 基于CyclicBarrier和CountDownLatch的使用區(qū)別說明

    基于CyclicBarrier和CountDownLatch的使用區(qū)別說明

    這篇文章主要介紹了基于CyclicBarrier和CountDownLatch的使用區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 關(guān)于SpringBoot中的跨域問題

    關(guān)于SpringBoot中的跨域問題

    這篇文章主要介紹了關(guān)于SpringBoot中的跨域問題,同源策略是由Netscape提出的一個著名的安全策略,它是瀏覽器最核心也最基本的安全功能,現(xiàn)在所有支持JavaScript的瀏覽器都會使用這個策略,需要的朋友可以參考下
    2023-08-08

最新評論