本文涉及:普通哈希算法存在的問題,分佈式系統的哈希一致性算法,哈希一致性算法中的數據傾斜問題程序員
咱們知道,在分佈式系統中當數據量沒法使用單機進行存儲時,最簡單粗暴的方法就是水平擴展:加機器,搞集羣。面試
然而全部的集羣模式都會面臨一個數據存放的問題:即一個集羣有多臺機器,咱們怎麼知道此次的數據應該放在哪一個機器上呢?此次的數據放到了一臺機器上我下一次讀取的時候能保證還來這臺機器上找麼?算法
假如當前咱們有一個Redis集羣,共5個節點對外提供服務bash
◆
Hash取模
◆服務器
最開始的解決方案就是首先給5臺機器分別編號:一、二、三、四、5
當對一個數據進行操做時首先計算key的hash而後對機器數量5進行取餘,得出的餘數就是須要放置的機器的編號。多線程
1複製代碼 |
key應該放置的機器編號=hash(key) % 5複製代碼 |
這個方案完美解決了文章開始提到的兩個問題,可是你們都知道,程序員的智力是沒有上限,固然主要是由於問題逼的:分佈式
若是其中一臺機器宕機了、或者新增了服務器,則整個集羣全部的數據都須要從新計算位置,這個過程簡直不要太痛苦。源碼分析
◆
一致性Hash
◆學習
既然出現了問題,聰明的程序員很快就想到了解決方案:一致性哈希算法
ui
如上圖所示,程序員們把全部的機器模擬成了一個虛擬的哈希環,而後設計了一個空間的大小,這個空間被平均分配到了全部機器的中間。當須要對一個key操做時,一樣進行進行取模運算,只不過這裏的模再也不是機器數量而是空間大小,而後根據得出的結果,去離結果順時針最近的一個節點上操做key。
例如:當一個集羣有5個節點、空間大小被設置爲500的時候,當要設置一個key的hash值爲601時。首先會對key的hash進行取餘,601%500 結果爲101,而後根據結果101順時針查找最近的節點找到了192.168.1.3。
同理,設置另外一個key,先算hash,假如是888,則首先取餘得出結果388而後得出節點192.168.1.5。
使用Hash一致性的時候若是遇到了節點宕機或者新增服務器的狀況下可就簡單的多了:
節點宕機,只須要把宕機節點的數據遷移到順時針的下一個服務器上
新增節點僅僅須要遷移逆時針的第一臺服務器的部分數據
◆
數據傾斜
◆
一致性哈希算法完美的解決了普通的哈希算法的問題,可是呢,沒有十全十美的算法,一致性哈希算法一樣存在一些問題。由上方的示例咱們能夠看出來,當集羣內擴縮容次數多了之後,數據很容易出現不均勻的狀況,有的機器負責了大半的空間,而有的機器僅僅負責一點點空間。這個問題有一個名詞,數據傾斜:
爲了解決數據傾斜問題,一致性哈希算法引入了虛擬節點機制,即將每個服務節點都計算爲多個虛擬節點,避免單個節點持有連續的大空間: