哈希算法
一致性哈希提出了在動態變化的Cache環境中,哈希算法應該滿足的4個適應條件:
均衡性(Balance)
平衡性是指哈希的結果能夠儘可能分布到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。很多哈希算法都能夠滿足這一條件。
單調性(Monotonicity)
單調性是指如果已經有一些內容通過哈希分派到了相應的緩衝中,又有新的緩衝區加入到系統中,那么哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩衝區中去,而不會被映射到舊的緩衝集合中的其他緩衝區。(這段翻譯信息有負面價值的,當緩衝區大小變化時一致性哈希(Consistent hashing)儘量保護已分配的內容不會被重新映射到新緩衝區。)
簡單的哈希算法往往不能滿足單調性的要求,如最簡單的線性哈希:
x → ax + b mod (P)在上式中,P表示全部緩衝的大小。不難看出,當緩衝大小發生變化時(從P1到P2),原來所有的哈希結果均會發生變化,從而不滿足單調性的要求。
哈希結果的變化意味著當緩衝空間發生變化時,所有的映射關係需要在系統內全部更新。而在P2P系統內,緩衝的變化等價於Peer加入或退出系統,這一情況在P2P系統中會頻繁發生,因此會帶來極大計算和傳輸負荷。單調性就是要求哈希算法能夠應對這種情況。
分散性(Spread)
在分散式環境中,終端有可能看不到所有的緩衝,而是只能看到其中的一部分。當終端希望通過哈希過程將內容映射到緩衝上時,由於不同終端所見的緩衝範圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內容被不同的終端映射到不同的緩衝區中。這種情況顯然是應該避免的,因為它導致相同內容被存儲到不同緩衝中去,降低了系統存儲的效率。分散性的定義就是上述情況發生的嚴重程度。好的哈希算法應能夠儘量避免不一致的情況發生,也就是儘量降低分散性。
負載(Load)
負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容映射到不同的緩衝區中,那么對於一個特定的緩衝區而言,也可能被不同的用戶映射為不同的內容。與分散性一樣,這種情況也是應當避免的,因此好的哈希算法應能夠儘量降低緩衝的負荷。
從表面上看,一致性哈希針對的是分散式緩衝的問題,但是如果將緩衝看作P2P系統中的Peer,將映射的內容看作各種共享的資源(數據,檔案,媒體流等),就會發現兩者實際上是在描述同一問題。
路由算法
在一致性哈希算法中,每個節點(對應P2P系統中的Peer)都有隨機分配的ID。在將內容映射到節點時,使用內容的關鍵字和節點的ID進行一致性哈希運算並獲得鍵值。一致性哈希要求鍵值和節點ID處於同一值域。最簡單的鍵值和ID可以是一維的,比如從0000到9999的整數集合。
根據鍵值存儲內容時,內容將被存儲到具有與其鍵值最接近的ID的節點上。例如鍵值為1001的內容,系統中有ID為1000,1010,1100的節點,該內容將被映射到1000節點。
為了構建查詢所需的路由,一致性哈希要求每個節點存儲其上行節點(ID值大於自身的節點中最小的)和下行節點(ID值小於自身的節點中最大的)的位置信息(IP位址)。當節點需要查找內容時,就可以根據內容的鍵值決定向上行或下行節點發起查詢請求。收到查詢請求的節點如果發現自己擁有被請求的目標,可以直接向發起查詢請求的節點返回確認;如果發現不屬於自身的範圍,可以轉發請求到自己的上行/下行節點。
為了維護上述路由信息,在節點加入/退出系統時,相鄰的節點必須及時更新路由信息。這就要求節點不僅存儲直接相連的下行節點位置信息,還要知道一定深度(n跳)的間接下行節點信息,並且動態地維護節點列表。當節點退出系統時,它的上行節點將嘗試直接連線到最近的下行節點,連線成功後,從新的下行節點獲得下行節點列表並更新自身的節點列表。同樣的,當新的節點加入到系統中時,首先根據自身的ID找到下行節點並獲得下行節點列表,然後要求上行節點修改其下行節點列表,這樣就恢復了路由關係。
結論
一致性哈希基本解決了在P2P環境中最為關鍵的問題——如何在動態的網路拓撲中分布存儲和路由。每個節點僅需維護少量相鄰節點的信息,並且在節點加入/退出系統時,僅有相關的少量節點參與到拓撲的維護中。所有這一切使得一致性哈希成為第一個實用的DHT算法。
但是一致性哈希的路由算法尚有不足之處。在查詢過程中,查詢訊息要經過O(N)步(O(N)表示與N成正比關係,N代表系統內的節點總數)才能到達被查詢的節點。不難想像,當系統規模非常大時,節點數量可能超過百萬,這樣的查詢效率顯然難以滿足使用的需要。換個角度來看,即使用戶能夠忍受漫長的時延,查詢過程中產生的大量訊息也會給網路帶來不必要的負荷。
使用二分查找算法可以將時間複雜度降低為O(log2n)
英文解釋
Consistent hashing is a scheme that provides hash table functionality in a way that the addition or removal of one slot does not significantly change the mapping of keys to slots.