簡介
在分散式叢集中,對機器的新增、刪除或者是機器故障後自動脫離叢集等操作是分散式叢集管理最基本的功能。如果採用的是常見的取模雜湊演算法,當有機器新增、刪除之後,需要對資料做遷移,非常麻煩。
而一致性雜湊利用雜湊環的概念,保證增加或減少伺服器,資料儲存的改變最少,相比取模雜湊演算法大大節省了資料移動的開銷,非常方便。
一致性雜湊認為在動態變化的快取空間環境中,良好的雜湊演算法應該滿足以下幾個方面:
- 平衡性:指雜湊的結果能夠儘可能分佈到所有的快取中,這樣可以使得所有的快取空間都能得到利用
- 單調性:指當新的快取空間加入時,原本已分配的資料可以被對映到原本或者新的快取空間中,而不會被對映到舊的其他快取空間中
- 分散性:避免出現相同的內容被不同的終端對映到不同的快取空間中,降低系統儲存的效率
- 負載:與分散性結合理解,對於一個特定的緩衝區,避免被不同的終端對映為不同的內容
一致性雜湊可以理解成普通取模雜湊演算法的改良版,改變的是將普通的線性雜湊空間變成環狀的雜湊空間,其中每一個快取空間是環上的一個節點,資料一般儲存在沿順時針的方向找到的環上的第一個節點。
演算法
雜湊環
簡單的說,一致性雜湊是將整個雜湊值空間想象成一個虛擬的圓環。
比如,假設雜湊函式 H 的值空間為 0 ~ \(2^{32}-1\),整個雜湊空間環如下:
假設這時有 k1、k2、k3、k4 這幾個 key 值,通過一定的雜湊演算法,將這幾個 key 值被平均分配到雜湊環上。
同樣的,現在有 3 臺 cache 伺服器,通過一定的雜湊演算法,也被平均分配到雜湊環上。
下圖展示的是 key 值被分配到哪一臺 cache 伺服器的一個示例:
如上所示:k1 儲存在 c3 上,k4、k3 儲存在 c1 上,k2 儲存在 c2 上。
雜湊環會將雜湊後的 key 值按照順時針的方向尋找最近的 cache 伺服器,然後將資料儲存在這臺伺服器上。
刪除節點
假設 c3 伺服器當機,這時候需要從叢集中將其摘除,其上的資料也需要做遷移。
按照一致性雜湊的規則,原本儲存在 c3 上的 k1 按照順時針的方向尋找最近的 cache 伺服器,即後續 k1 會儲存在 c1 上:
從這裡可知,當使用一致性雜湊時,刪除節點 c3 會影響到被刪除節點 c3 上及其下一個節點 c1 的資料,遷移資料的時候,需要將被刪除節點 c3 上的資料遷移到其下一個節點 c1 上。
新增節點
假設現在需要新增 c4 伺服器,會破壞現在叢集的平衡,需要對資料做一些處理。
假設 c4 伺服器定位在 k4 和 k3 之間,按照一致性雜湊的規則,原本儲存在 c1 上的 k4 會遷移到 c4 上:
同樣的,新增節點會影響到新增節點所在位置的後一個節點 c1,遷移資料的時候,需要將新增節點所在位置到其上一個節點 c3 之間的資料從其下一個節點 c1 遷移到新增的節點 c4 上。
虛擬節點
一致性雜湊理論上沒有什麼問題,但實際使用會存在以下問題:
- 當節點較少時,雜湊環中的節點容易出現分佈不均衡,最終導致資料傾斜
- 當一個節點當機時,資料會立馬遷移到下一個節點,下一個節點的流量壓力和記憶體壓力都會增大,可能會導致其當機,繼而引發雪崩
這裡就衍生出一個虛擬節點的概念,即對每個物理節點計算多個雜湊值,將原來單一的物理節點在雜湊環上虛擬出幾個分身節點,這些分身節點稱為虛擬節點。
對映到分身節點上的資料實際上就是對映到分身對應的物理節點上,這樣一個物理節點可以通過虛擬節點的方式均勻分散在雜湊環的各個部分,解決資料傾斜問題。
由於虛擬節點分散在雜湊環各個部分,當某個節點當機下線,虛擬節點所儲存的資料會被均勻分配給下一個虛擬節點,則物理節點也會得到均勻分配,避免了對單一節點突發壓力導致的節點雪崩問題。
在實際應用中,通常將虛擬節點數設定成 32 甚至更大,這樣可以保證即使很少的服務節點也能做到均勻的資料分佈。
優缺點
一致性雜湊演算法相比普通的雜湊演算法在擴充套件性和容錯性上都有一定的優勢:
- 擴充套件性:普通的雜湊演算法增加快取空間的時候,需要對大量資料做遷移;一致性雜湊演算法擴充套件時僅需將下一個節點中的一部分資料遷移到這個新增節點上
- 容錯性:普通的雜湊演算法減少快取空間的時候,會出現雜湊對映大面積失效的情況;而對於一致性雜湊演算法,如果出現需要減少快取空間的情況,其實就是需要將當前減少的節點資料遷移到下一個節點中
實際上,不會存在一勞永逸的雜湊演算法,一致性雜湊演算法在以下場景需要謹慎使用:
- 對於資料佔用空間大、但數量較小時,使用一致性雜湊有些大材小用
- 一致性雜湊解決了資料的均勻分佈,但是沒有解決流量和負載的均衡
- 資料和機器之間的對映通過雜湊演算法得到,這種關係比較固定,無法人工干涉