【算法基礎】就算是最忙的你,也能理解一致性Hash算法

一致性Hash算法背景

一致性哈希算法在1997年由麻省理工學院的Karger等人在解決分佈式Cache中提出的,設計目標是爲了解決因特網中的熱點(Hot spot)問題,初衷和CARP十分類似。一致性哈希修正了CARP使用的簡單哈希算法帶來的問題,使得DHT可以在P2P環境中真正得到應用。

假設有 N 個 cache 服務器(後面簡稱 cache ),那麼如何將一個對象 object 映射到 N 個 cache 上呢,你很可能會採用類似下面的通用方法計算 object 的 hash 值,然後均勻的映射到到 N 個 cache

hash(object)%N

一切都非常的正常,假如有一下的兩種場景:

  • 一個 cache 服務器 m down 掉了(在實際應用中必須要考慮這種情況),這樣所有映射到 cache m 的對象都會失效,這時候,需把 cache m 從 cache 中移除,這時候 cache 是 N-1 臺,映射公式變成了 hash(object)%(N-1) ,數據丟失。
  • 由於訪問加重,需要添加 cache ,這時候 cache 是 N+1 臺,映射公式變成了 hash(object)%(N+1)

注意,此時映射公式的取模模量改變,意味着之前所有的cache都失效了。對於服務器而言,需要對原來所有的cache遷移到新的服務器中。

  • 硬件能力越來越強,可能想讓後添加的節點負載多一些,顯然上面的 hash 算法完成不了。
    有什麼可以改變,Consisten hashing可以解決。

hash算法和單調性

Hash 算法的一個衡量指標是單調性(Monotonicity ),定義如下:

單調性是指如果已經有一些內容通過哈希分派到了相應的服務器中,又有新的服務器加入到系統中。哈希的結果應能夠保證原有已分配的內容可以被映射到新的服務器中去,而不會被映射到添加之前的服務器集合中的其他服務器中。

顯然,hash(object)%N無法達到要求。

Consistent Hashing 一致性hash的原理

consistent hashing是一種hash算法,通俗的說,在移除或者是添加一臺服務器的時候,使以儘可能小的數據遷移代價去改變原有的key映射關係,從而去滿足單調性的要求。
如何做到?先從結構開始談起。

1.環形hash空間

考慮通常的 hash 算法都是將 value 映射到一個 32 位的 key 值,也即是 0~2^32-1 次方的數值空間。我們就可將其看作爲首尾相接的環。如下圖1:

在這裏插入圖片描述

圖1 一致性hash算法的環狀結構

2.把需要緩存的內容通過hash計算映射到hash空間

假設有四個對象object1~object4,通過hash函數計算的hash值key在環上的分佈如圖2所示。

實際可能不是這麼均勻

在這裏插入圖片描述

圖2 各個對象key映射到環中

3.把服務器(節點)映射到hash空間

Consistent hashing 的基本思想就是將對象和 服務器(節點)都映射到同一個 hash 數值空間中,使用是同種的 hash算法。
假設當前有 A,B 和 C 共 3 臺服務器(節點),其映射結果將如圖 3 所示,他們在 hash 空間中,以對應的 hash 值排列。
一般可以通過服務器的ip,mac地址…作爲hash輸入。實際並上不會這麼均勻:

hash(M_A) = key A;
hash(M_B) = key B;
hash(M_C) = key C;

在這裏插入圖片描述

圖3 對象映射到節點關係
4.把對應的對象映射到節點

現在服務器(節點)和對象都通過相同的hash算法映射到hash數值空間中。那麼,如何將對象映射到服務器(節點)上。
使用的策略是:將當前對象節點,按照順時針方向出發,第一個遇到的節點,就是當前對象要存儲的節點。由於對象和節點的hash值是固定的,所以節點必然是唯一和確定的。上圖3所示。

  • 4.1如何實現?

所想可以對所有的節點hash值進行排序,假設還是上面的三個節點,排序之後的序列,我假設爲se_M = [m2 , m1 , m3 ] , 通過前端負載的服務器,每個前端的服務器都保存有序列se_M,對每次來臨的請求對象進行hash值計算,使用二分法在序列中查找到首個大於或等於當前對象hash值的節點,將對象存儲到節點中,就可以實現將對應的對象映射到對應的節點中。

5.服務器(節點)變動情況

文章開始提到通過hash求餘計算出節點的最大問題在於無法滿足單調性,當節點有所變動時,節點中的數據有可能丟失(節點down),或者是數據遷移代價過高(新增節點),來直接的對後臺服務器進行衝擊。
consistent hashing如何解決?

  • 5.1 移除節點

假設此時M_B突然down了,根據上面的對象映射到節點的方法,此時受影響的僅僅是沿M_AM_B順時針路徑上的對象。也就是本來應該映射到M_B上的對象。

在這裏插入圖片描述

圖4 M_B被移除之後的映射
  • 5.2 添加節點

考慮添加一臺新的節點M_D 的情況,假設在這個環形 hash 空間中, M_D被映射在對象 object3 和object4 之間。這時受影響的將僅是那些沿 M_A 順時針直到下一個 M_D之間的對象(它們是也本來映射到M_B 上對象的一部分),將這些對象重新映射到 M_D 上即可,如圖5.
在這裏插入圖片描述

圖 5 添加 節點D 後的映射關係

上述這個結構還存在非常大的問題。首先,根據hash函數的性質易知樣本量在比較大的情況下,才體現出均分的性質,樣本量小時並不保證均分。於是上面的環就不可能被均勻的拆分。其次,即使你可以通過某種蜜汁手段來保證開始的時候能夠被均分,在節點增減的過程中,均分的結構又被破壞了。
如果能解決上述問題,一致性hash算法就既能做到數據遷移的代價很低又能夠做到負載均衡.

6. 虛擬節點

虛擬節點技術可以完美的解決上述兩個問題。以上述中三個節點M_A,M_B,M_C爲例子,摒棄直接以節點中ip,mac等等計算hash值的方法去映射環中的位置。而是給M_A,M_B,M_C分別分配數量比較大的虛擬節點,然後,通過分別計算虛擬節點的hash值,來將各個節點中的虛擬節點分配到環中對應的位置,這樣通過比較大的樣本量,通過hash函數性質易知,就能夠達到每個節點對應的虛擬節點在環中均分的目的。
對於虛擬節點和物理節點的問題,可以利用一個路由表結構,將物理機和虛擬節點一一對應起來,在環中對象映射到虛擬節點時,通過路由表查詢到對應的物理節點,對象映射到虛擬節點的操作實質上變成了對象映射到虛擬節點所對應的物理節點上。
這樣就解決了在減少或者是增加節點的時候,造成環的不均分問題。

【可能帶來的問題】:可能虛擬節點過多,會造成虛擬節點重疊問題。
小概率事件

參考博文:
百度百科_)一致性哈希
https://www.cnblogs.com/lpfuture/p/5796398.html
http://www.zsythink.net/archives/1182

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章