一致性哈希算法在1997年由麻省理工學院提出,是一種特殊的哈希算法,目的是解決分布式緩存的問題。 在移除或者添加一個服務器時,能夠盡可能小地改變已存在的服務請求與處理請求服務器之間的映射關系。一致性哈希解決了簡單哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的動態伸縮等問題。
01 —
場景描述
我們有三臺緩存服務器,用于緩存圖片,我們為這三臺緩存服務器編號為0號、1號、2號,現在,有3萬張圖片需要緩存,我們希望這些圖片被均勻的緩存到這3臺服務器上,以便它們能夠分攤緩存的壓力。 02 — 普通hash方式 hash(圖片名稱) % 3 3為服務器數量。對文件或圖片名稱進行hash,得出的結果應該是不變的,如果我們有3臺服務器,使用哈希后的結果對3求余,那么余數一定是0、1或者2,正好對應服務器編號
缺陷:當一臺服務器出現問題,或者增加一臺服務器時,所有數據都要重新緩存。會引起緩存的雪崩,可能會引起整體系統壓力過大而崩潰。
03 —
一致性hash說明
我們把2的32次方想象成一個圓,就像鐘表一樣,鐘表的圓可以理解成由60個點組成的圓,而此處我們把這個圓想象成由2^32個點組成的圓

正上方的點代表0,0點右側的第一個點代表1,以此類推,2、3、4、5、6……直到2^32-1,也就是說0點左側的第一個點代表2^32-1,構成一個hash環。
上面的三臺服務器,我們可以通過公式:hash(服務器A的IP地址) % 2^32
通過公式可以把三臺服務器分布到環上。

圖片數據公式:hash(圖片名稱) % 2^32
通過上面公式,我們可以把所有圖片分布hash環上,順時針找到最近服務器

一致性哈希算法就是通過這種方法,判斷一個對象應該被緩存到哪臺服務器上的,將緩存服務器與被緩存對象都映射到hash環上以后,從被緩存對象的位置出發,沿順時針方向遇到的第一個服務器,就是當前對象將要緩存于的服務器,由于被緩存對象與服務器hash后的值是固定的,所以,在服務器不變的情況下,一張圖片必定會被緩存到固定的服務器上,那么,當下次想要訪問這張圖片時,只要再次使用相同的算法進行計算,即可算出這個圖片被緩存在哪個服務器上,直接去對應的服務器查找對應的圖片即可
04
—
一致性hash優點
某臺服務器出現故障,我們現在需要將服務器B移除,那么,我們將上圖中的服務器B從hash環上移除即可,移除服務器B以后示意圖如下:

當服務器B移除以后,按照之前描述的一致性哈希算法的規則,圖片3應該被緩存到服務器C中。其它節點緩存服務器不變。不會出現全部重新緩存的情況。
05 —
hash傾斜
一致性哈希的概念時,我們理想化的將3臺服務器均勻的映射到了hash環上,如下圖所示:

理想很豐滿,現實很骨感,我們想象的與實際情況往往不一樣

如果服務器分布不均,很可能出現下圖這樣:

1號、2號、3號、4號、6號圖片均被緩存在了服務器A上,只有5號圖片被緩存在了服務器B上,服務器C上甚至沒有緩存任何圖片。極端情況下,仍然有可能引起系統的崩潰。
上面的問題可以通過虛擬節點方式解決:
憑空的讓服務器節點多起來,既然沒有多余的真正的物理服務器節點,我們就只能將現有的物理節點通過虛擬的方法復制出來,這些由實際節點虛擬復制而來的節點被稱為”虛擬節點

“虛擬節點”是”實際節點”(實際的物理服務器)在hash環上的復制品,一個實際節點可以對應多個虛擬節點。
A、B、C三臺服務器分別虛擬出了一個虛擬節點,當然,如果你需要,也可以虛擬出更多的虛擬節點。引入虛擬節點的概念后,緩存的分布就均衡多了。