consistent hash 原理,優化及實現

Charles0429發表於2018-11-26

引言

在分散式環境中,由於資料量龐大,往往需要對資料做分割槽,分割槽有兩種:一種是range分割槽,另一種是hash分割槽。顧名思義,hash分割槽是採用hash演算法,將資料劃分到不同的分割槽中,採用傳統的hash演算法能有效地將資料劃分到不同的分割槽,但是,傳統的hash演算法在機器上下線時,由於hash對映的變化,會導致大量的資料發生遷移。本文以分散式快取為場景,分析了傳統hash演算法的缺點,並討論了consistent hash如何解決該問題,以及consistent hash的優化和實現。

本文的按如下組織:

  • 傳統hash演算法的缺點
  • consistent hash

本文同步在我的部落格oserror.com

同時本文收錄在我的github中papers專案,papers專案旨在學習和總結分散式系統相關的論文。

傳統hash演算法的缺點

以分散式快取場景為例,如下:

consistent hash 原理,優化及實現
traditional hash

對於傳統hash分割槽方法,針對某個(key,value)對,其儲存的快取節點下標可以用hash(key) % N,在正常情況下,能良好地工作。但是,當機器當機當機下線時,可能會涉及到大量的資料的遷移,因為機器數量減少為N-1,對應的hash取模後,大量的(key,value)對到Cache Server的對映發生改變,導致大量的(key,value)資料在Cache Server間遷移,以一個例子說明這個問題:

假設hash函式為y = x + 1,系統中有如下(key,value)對,機器數量為5臺

(0,1)
(1,2)
(2,3)
(3,4)
(4,5)複製程式碼

根據hash函式取模,得到(key,value)到Cache Server的如下對映:

(0,1) -> Cache Server 1
(1,2) -> Cache Server 2
(2,3) -> Cache Server 3
(3,4) -> Cache Server 4
(4,5) -> Cache Server 5複製程式碼

假設其中Cache Server 1當機,(key, value)到Cache Server重新對映如下:

(0,1) -> Cache Server 2
(1,2) -> Cache Server 3
(2,3) -> Cache Server 4
(3,4) -> Cache Server 2
(4,5) -> Cache Server 4複製程式碼

可以看出,上述極端例子中,所有的(key,value)對都發生了遷移,這個開銷是相當大的。在分散式系統中,由於機器數量眾多,機器發生故障是常態,因此,採用傳統的hash演算法是不合適的。

consistent hash

為了解決上述問題,引入了consistent hash演算法,如下圖:

consistent hash 原理,優化及實現
consistent hash

在consistent hash中,有一個hash環,代表一個範圍,例如,可以取值為[0,2^64-1]。對於,每個Cache Server會根據hash函式算出一個整數值,最終落到hash環的某個點上,如圖中的Cache Server 1-5。每個(key,value)對儲存在hash環上順時針的下一個Cache Server,舉個例子,假設hash(Cache Server i) = Hi,i=1..5,如果(1,2)的hash取值處於[H1,H2)之間的話,那麼它會儲存在Cache Server2上,以此類推。

因此,consistent hash能很好地應對Cache Server當機情況,假設還是Cache Server 1當機,如下圖:

consistent hash 原理,優化及實現
consistent hash server down

上圖中Cache Server 1發生當機的話,整個系統中只有(0,1)會從當機的Cache Server 1遷移到Cache Server 2,比傳統的hash演算法會好很多。

但上述的consistent hash也有其缺點:

  • Cache Server在hash環上的分佈可能不均勻,導致Cache Server間的負載不均衡
  • Cache Server的配置可能不同,所以能承受的負載也不同,而上述的consistent hash是沒有考慮這個因素的

為了說明上述問題,我實現了上述的consistent hash演算法,並且模擬了10000個key,10臺機器的場景下各個server的負載情況如下

Node1:324
Node6:689
Node3:75
Node2:217
Node5:28
Node8:865
Node0:657
Node9:3157
Node4:2284
Node7:1704複製程式碼

可以看出機器之間的負載不均衡程度很高,為此,引入了虛擬節點的概念。一個實際的Server可以拆分成多個虛擬節點,虛擬節點根據hash值會散落在hash環的不同地方,這樣,在虛擬節點個數較大時,負載就會趨向於均衡。

下面做了一組實驗,模擬了虛擬節點的數量從1,10,50,100,200,400,800的時候,各個Cache Server的負載均衡情況:

consistent hash 原理,優化及實現
consistent hash data

其中橫座標是每個Server的虛擬節點的數量,縱座標是每個Server負載量的標準偏差,反映了Server之間負載的不均衡度,從圖中看出,當虛擬節點的數量增加時,Server之間的不均衡度下降了。

虛擬節點除了用來降低Server的不均衡度之外,還可以用來表示每個Server的容量情況,例如,對於負載能力為1的Server,可以給它分配1個虛擬節點,而對於負載能力為10的Server,可以給它分配10個虛擬節點,從而為異構的Server提供相應的支援。

本文的程式碼在consistent_hash.cpp,使用方法在ReadMe

PS:
本部落格更新會在第一時間推送到微信公眾號,歡迎大家關注。

consistent hash 原理,優化及實現
qocde_wechat

參考文獻

相關文章