1.簡述
1.1.哈希算法
哈希算法:將任意長度的輸入通過散列算法轉換成固定長度的輸出。
哈希算法是一種映射算法,將任意個數的輸入映射爲固定個數的哈希值。
1.2.應用場景舉例
分佈式緩存
現有用戶數據3000萬,爲提高訪問速度,將用戶基本信息保存在緩存中,其中:
- key=user:{uid},其中uid爲用戶ID,由UUID生成。value爲姓名、賬號級別等構成的Json串。
- 爲了分擔單臺服務器壓力,將緩存數據分攤在3臺服務器上。
- 爲了能夠快速定位某個用戶所在的服務器,通過
key % 3
的哈希算法分配圖片的存儲位置。 - 理想情況下,服務器node2有1000萬用戶信息,相當於1000萬個key經過哈希都映射爲哈希值2.
其他應用:
- 數據庫分表
1.3.普通哈希算法的缺陷
正常情況下,上述哈希算法是沒有問題的。
但是,因爲一些原因,需要增減服務器,這是必然導致哈希算法的變化,例如變爲 key % 5
。
當哈希算法的模數發送變化時,原有的映射值幾乎全部失效,需要重新映射幾乎全部數據,這個工作量十分巨大。
缺陷總結:當增加或移除節點時,普通哈希算法幾乎需要重新映射全部關鍵字。
一致性哈希算法能夠在一定程度上解決上述缺陷。
2.一致性哈希算法
一致性哈希
是一種特殊的哈希算法。
在使用一致哈希算法後,節點的改變平均只需要對K/N 個關鍵字重新映射,其中K是關鍵字的數量,N是節點數量。
下面分表講述一致性哈希的幾個關鍵問題:算法步驟、節點增減、哈希偏斜、虛擬節點。
2.1.算法步驟
哈希算法也是一種取模
算法,只是,模數固定爲2^32
,也就是說哈希值範圍:0
~ (2^31 - 1)
,如下圖所示:
一致性哈希環:
- 圖中的圓環稱之爲
一致性哈希環
,由2^32
個節點構成。。 - 節點按照順時針排列,正上方節點爲0,節點0的左側相鄰節點爲
2^31-1
節點。
一致性哈希算法:
- 對服務器進行
ip % (2^32)
哈希,結果如圖中綠色的點所示。 - 對key進行
key % (2^32)
哈希,結果如同種紫色的點所示。 - 判斷key所屬服務器:從紫色點的位置開始,順時針探索,遇到的第一個綠色的點,就是其所屬的服務器。
2.2.增減節點
那麼,一致性哈希算法,如何在一定程度上解決節點增減引起的問題呢?如下圖所示:
節點增加:
- 圖中節點D爲新增節點。
- 此時,只需將
節點D
至節點B
之間的key重新映射
至節點D
即可,圖中只有1個key受此影響。
節點減少:
- 圖中節點A爲移除節點。
- 此時,只需將
節點A
至節點C
之間的key重新映射
至節點BB
即可,圖中只有3個key受此影響。
總結:(理想情況下)
- 假定共有K個key和N個節點,每個節點上存儲K/N個key。
- 當新增節點時,只需將
新增節點內
至新增節點的上個節點
之間的key重新映射至新增節點
即可,共計(K/N)/2個key。 - 當移除節點時,只需將
移除節點
至移除節點的上個節點
之間的key重新映射至移除節點的下個節點
即可,共計(K/N)個key。 - 所以說,一致性哈希能夠在一定程度上解決增減節點的問題,而不是完全解決。
2.3.哈希偏斜
討論哈希問題,必然需要討論哈希偏斜問題。下圖就是一致性哈希偏斜的例子:
如圖中所示:
- 節點A上映射了9個key,而節點C上只映射了1個key。
- 這種情況下,理論上,服務器A需要承受的壓力是服務器C的9倍。
那麼,一致性哈希如何解決哈希偏斜問題,這就需要進入虛擬節點
的概念了。
2.4.虛擬節點
下圖就是增加了虛擬節點的一致性哈希環:
如圖所示:
- 深綠色節點爲實際服務器的哈希結果,淺綠色節點爲虛擬節點。
- 虛擬節點如何產生?很多種方法,如:
ip+number % (2^32)
。 - 如圖,虛擬節點B1和B2都是服務器B的IP+順序號進行一致性哈希算法生成的,所以映射到B1和B2的key其實還是映射到了節點B上。
- 增加虛擬節點之後,節點A、B、C上分別映射了3、4、5個節點,偏斜情況大大改觀。
總結:
- 在一致性哈希算法中,可以通過虛擬節點解決哈希偏斜問題。
- 理論上,增加的虛擬節點越多,哈希值分佈越平均。
- 當然,也要注意虛擬節點的生成算法是否合理,生成的虛擬節點是否分佈平均。