最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ava實(shí)現(xiàn)一致性Hash算法

 更新時(shí)間:2023年03月24日 09:29:26   作者:何憶清風(fēng)  
本文主要詳細(xì)介紹了Java如何實(shí)現(xiàn)一致性Hash算法,其實(shí)現(xiàn)原理將key映射到?2^32?-?1?的空間中,將這個(gè)數(shù)字的首尾相連,形成一個(gè)環(huán)。想了解更多的同學(xué),可以參考本文

1. 實(shí)現(xiàn)原理

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

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

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

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

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

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

解決

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

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

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

3. 代碼實(shí)現(xiàn)

3.1 ConsistentHash

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

public class ConsistentHash<T> {

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

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

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

    //默認(rèn)虛擬節(jié)點(diǎn)數(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é)點(diǎn)個(gè)數(shù)來計(jì)算虛擬節(jié)點(diǎn)
            for (int i = 0; i < this.replicas; i++) {
                //根據(jù)函數(shù)獲取到對(duì)應(yīng)的hash值
                int hash = this.hashMethod.hash(i + ":" + key.toString());
                this.keys.add(hash);
                this.hashMap.put(hash, key);
            }
        }
        //排序,因?yàn)槭且粋€(gè)環(huán)狀結(jié)構(gòu)
        Collections.sort(this.keys);
    }

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

3.2 Hash

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

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

3.3 Utils

由于hashcode采用的int類型進(jìn)行存儲(chǔ),那么就需要考慮,hash是否超過了int最大存儲(chǔ),如果超過了那么存儲(chǔ)的數(shù)字就是負(fù)數(shù),會(huì)對(duì)獲取節(jié)點(diǎn)造成影響,所以這里在取hash值時(shí),采用了hashmap中獲取到hashcode之后對(duì)其進(jìn)行與操作,可以減少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) {
                //長(zhǎng)度除于2
                int h = (i + j) >> 1;
                //調(diào)用函數(shù),判斷當(dāng)前的索引值是否大于
                if (f.apply(h)) {
                    //向低半段進(jìn)行遍歷
                    j = h;
                } else {
                    //向高半段進(jìn)行遍歷
                    i = h + 1;
                }
            }
            return i;
        }

        /**
         * 將返回的hash能夠平均的計(jì)算在 int類型之間
         *
         * @param o
         * @return
         */
        public static int rehash(Object o) {
            int h = o.hashCode();
            return (h ^ (h >>> 16)) & HASH_BITS;
        }
    }

3.4 main

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

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é)點(diǎn)獲取錯(cuò)誤,key:" + k + ",獲取到的節(jié)點(diǎn)值為:" + 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é)點(diǎn)獲取錯(cuò)誤,key:" + k + ",獲取到的節(jié)點(diǎn)值為:" + node);
            }
        });
    }

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

相關(guān)文章

  • Spring事件監(jiān)聽機(jī)制使用和原理示例講解

    Spring事件監(jiān)聽機(jī)制使用和原理示例講解

    Spring事件監(jiān)聽機(jī)制是一個(gè)很不錯(cuò)的功能,我們?cè)谶M(jìn)行業(yè)務(wù)開發(fā)的時(shí)候可以引入,在相關(guān)的開源框架中也是用它的身影,比如高性能網(wǎng)關(guān)ShenYu中就使用了Spring事件監(jiān)聽機(jī)制來發(fā)布網(wǎng)關(guān)的更新數(shù)據(jù),它可以降低系統(tǒng)的耦合性,使系統(tǒng)的擴(kuò)展性更好
    2023-06-06
  • 基于mybatis-plus 時(shí)間字段比較

    基于mybatis-plus 時(shí)間字段比較

    這篇文章主要介紹了mybatis-plus 時(shí)間字段的比較,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 詳解Spring Boot 使用Spring security 集成CAS

    詳解Spring Boot 使用Spring security 集成CAS

    本篇文章主要介紹了詳解Spring Boot 使用Spring security 集成CAS,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 使用IDEA創(chuàng)建一個(gè)vert.x項(xiàng)目的方法

    使用IDEA創(chuàng)建一個(gè)vert.x項(xiàng)目的方法

    這篇文章主要介紹了使用IDEA創(chuàng)建一個(gè)vert.x項(xiàng)目的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • Java中對(duì)集合的元素排序操作方法

    Java中對(duì)集合的元素排序操作方法

    本文介紹了Java中對(duì)集合元素進(jìn)行排序的幾種常見方法,包括使用Collections.sort()、List.sort()、StreamAPI以及對(duì)Map的鍵或值進(jìn)行排序,每種方法都有其適用的場(chǎng)景和使用方式,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Java單例模式簡(jiǎn)單示例

    Java單例模式簡(jiǎn)單示例

    這篇文章主要介紹了Java單例模式,結(jié)合實(shí)例形式簡(jiǎn)單分析了java單例模式的定義與使用技巧,需要的朋友可以參考下
    2017-06-06
  • 使用SpringBoot 工廠模式自動(dòng)注入到Map

    使用SpringBoot 工廠模式自動(dòng)注入到Map

    這篇文章主要介紹了使用SpringBoot 工廠模式自動(dòng)注入到Map,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring用代碼來讀取properties文件實(shí)例解析

    Spring用代碼來讀取properties文件實(shí)例解析

    這篇文章主要介紹了Spring用代碼來讀取properties文件實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • SpringBoot中引入MyBatisPlus的常規(guī)操作

    SpringBoot中引入MyBatisPlus的常規(guī)操作

    這篇文章主要介紹了SpringBoot中引入MyBatisPlus的常規(guī)操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Springboot通過url訪問本地圖片代碼實(shí)例

    Springboot通過url訪問本地圖片代碼實(shí)例

    這篇文章主要介紹了springboot通過url訪問本地圖片代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論

岳阳县| 滦南县| 修水县| 惠安县| 漳浦县| 保康县| 定襄县| 绍兴市| 东明县| 临沂市| 桂平市| 绿春县| 会泽县| 宜兰县| 凤翔县| 遂宁市| 登封市| 体育| 教育| 和政县| 武功县| 抚顺县| 呼伦贝尔市| 桦南县| 冀州市| 太白县| 涞水县| 马关县| 瑞昌市| 阿克苏市| 若尔盖县| 苍南县| 元氏县| 许昌市| 汽车| 宁海县| 保靖县| 新巴尔虎右旗| 通化县| 虹口区| 西林县|