<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一致性Hash算法Java版實現

          共 2398字,需瀏覽 5分鐘

           ·

          2021-02-20 12:17

          分布式緩存集群的訪問模型

          現在通常使用Redis來做分布式緩存,下面我們就以Redis為例:

          假如當前我們系統(tǒng)的業(yè)務發(fā)展很快,需要緩存的數據很多,所以我們做了一個由三組主從復制的redis組成的高可用的redis集群,如何將請求路由的不同的redis集群上,這是我們需要考慮的,常用的路由算法:

          「隨機算法」:每次將請求隨機的發(fā)送到其中一組Redis集群中,這種算法的好處是請求會被均勻的分發(fā)到每組Redis集群上;缺點也很明顯,由于隨機分發(fā)請求,為了提高緩存的命中率,所以同一份數據需要在每組集群中都存在,這樣就會造成了數據的冗余,浪費了存儲空間

          「Hash算法」:針對隨機算法的問題,我們可以考慮Hash算法,舉例:現在有三組redis集群,我們可以對每次緩存key的hash值取模,公式:index=hash(key) % 3,index的值就對應著3組集群,這樣就可以保證同一個請求每次都被分發(fā)到同一個redis集群上,無需對數據做冗余,完美的解決了剛才隨機算法的缺點;

          但是hash算法也有缺點:對于容錯性和伸縮性支持很差,舉例:當我們三組redis集群中其中一組節(jié)點宕機了,那么此時的redis集群中可用的數量變成了2,公式變成了index=hash(key) % 2, 所有數據緩存的節(jié)點位置就發(fā)生了變化,造成緩存的命中率直線下降;

          同理,當我們需要擴展一組新的redis機器,計算的公式index=hash(key) % 4,大量的key會被重新定位到其他服務器,也會造成緩存的命中率下降。

          為了解決hash算法容錯性和伸縮性的問題,一致性hash算法由此而生~

          一致性哈希算法

          具體的算法過程

          1. 先構造一個長度為2^32-1的整數環(huán)(稱為一致性hash環(huán)),然后給每組redis集群命名,根據名字的hash值計算出每組集群應該放在什么位置
          1. 根據緩存數據的key計算出hash值,計算出出來的hash值同樣也分布在一致性hash環(huán)上; 假如現在有5個數據需要緩存對應的key分別為key1、key2、key3、key4、key5,計算hash值之后的分布如下圖
          1. 然后順著hash環(huán)順時針方向查找reids集群,把數據存放到最近的集群上

          最后所有key4、key5存放在了集群2,key1、key3存放在了集群1,key2存放在了集群3

          容錯性

          還是繼續(xù)沿用上面的例子,我們來看下一致性哈希算法的容錯性如何呢?假如其中 集群1 跪了,那么影響的數據只有key1和key3,其他數據存放的位置不受影響;當再次緩存key1、key3的時候根據順時針查找,會把數據存放到集群3上面

          伸縮性

          如果我們需要在當前的基礎上再添加一組redis集群4,根據名字hash之后的位置在集群1和集群2之間

          新加redis集群4之后影響的只有key1數據,其他數據不受影響。

          數據傾斜問題

          經過容錯性、伸縮性的驗證證明了一致性哈希算法確實能解決Hash算法的問題,但是現在的算法就是完美的嗎?讓我們繼續(xù)來看剛才容錯性的例子,加入集群1跪了,那么原來落在集群1上的所有數據會直接落在集群3上面,如果說每組redis集群的配置都是一樣的,那么集群3的壓力會增大,數據分布不均勻造成數據傾斜問題。

          怎么搞呢?

          歪果仁的腦子就是好使,給的解決方案就是加一層虛擬層,假如每組集群都分配了2個虛擬節(jié)點

          集群虛擬節(jié)點
          集群1vnode1, vnode2
          集群2vnode3, vnode4
          集群3vnode5, vnode6

          接下來就是把虛擬節(jié)點放入到一致性hash環(huán)上,在緩存數據的時候根據順時針查找虛擬節(jié)點,在根據虛擬節(jié)點的和實際集群的對應關系把數據存放到redis集群,這樣數據就會均勻的分布到各組集群中。

          這時候如果有一組redis集群出現了問題,那么這組集群上面的key會相對均勻的分攤到其他集群上。

          從上面的結果來看,只要每組集群對應的虛擬節(jié)點越多,那么各個物理集群的數據分布越均勻,當新增加或者減少物理集群影響也會最小,但是如果虛擬節(jié)點太多會影響查找的性能,太少數據又會不均勻,那么多少合適呢?根據一些大神的經驗給出的建議是 「150」 個虛擬節(jié)點。

          一致性Hash算法Java版實現

          實現思路:在每次添加物理節(jié)點的時候,根據物理節(jié)點的名字生成虛擬節(jié)點的名字,把虛擬節(jié)點的名字求hash值,然后把hash值作為key,物理節(jié)點作為value存放到Map中;這里我們選擇使用TreeMap,因為需要key是順序的存儲;在計算數據key需要存放到哪個物理節(jié)點時,先計算出key的hash值,然后調用TreeMap.tailMap()返回比hash值大的map子集,如果子集為空就需要把TreeMap的第一個元素返回,如果不為空,那么取子集中的第一個元素。

          ?

          不扯廢話,直接上代碼,No BB . Show me the code

          ?

          核心代碼:

          測試代碼:

          1. 測試刪除節(jié)點node3,對比命中率影響了多少 添加如下代碼:

          執(zhí)行結果:

          1. 測試添加節(jié)點node5,對比命中率影響了多少 添加如下代碼:

          執(zhí)行結果:

          其他使用場景

          看上圖,在Nginx請求的分發(fā)過程中,為了讓應用本地的緩存命中率最高,我們希望根據請求的URL或者URL參數將相同的請求轉發(fā)到同一個應用服務器中,這個時候也可以選擇使用一致性hash算法。具體配置可以參考官方文檔:https://www.nginx.com/resources/wiki/modules/consistent_hash/


          源碼地址:https://github.com/silently9527/JavaCore


          瀏覽 84
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费一片A | 国产女人在线视频 | 精品传媒一区二区 | 粉嫩小泬BBBBBB免费 | 一级黄色艳情A片 |