您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Java語言Consistent Hash算法怎么用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Java語言Consistent Hash算法怎么用”這篇文章吧。
一致性哈希算法在1997年由麻省理工學院提出(參見0),設計目標是為了解決因特網中的熱點(Hot pot)問題,初衷和CARP十分類似。一致性哈希修正了CARP使用的簡單哈希算法帶來的問題,使得DHT可以在P2P環境中真正得到應用。
一致性哈希提出了在動態變化的Cache環境中,哈希算法應該滿足的4個適應條件:
平衡性是指哈希的結果能夠盡可能分布到所有的緩存中去,這樣可以使得所有的緩存空間都得到利用。很多哈希算法都能夠滿足這一條件。
單調性是指如果已經有一些內容通過哈希分派到了相應的緩存中,又有新的緩存加入到系統中。哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩存中去,而不會被映射到舊的緩存集合中的其他緩沖區。
簡單的哈希算法往往不能滿足單調性的要求,如最簡單的線性哈希:
x → ax + b mod (P)
在上式中,P表示全部緩存的大小。不難看出,當緩存大小發生變化時(從P1到P2),原來所有的哈希結果均會發生變化,從而不滿足單調性的要求。
哈希結果的變化意味著當緩存空間發生變化時,所有的映射關系需要在系統內全部更新。而在P2P系統內,緩存的變化等價于Peer加入或退出系統,這一情況在P2P系統中會頻繁發生,因此會帶來極大計算和傳輸負荷。單調性就是要求哈希算法能夠避免這一情況的發生。
在分布式環境中,終端有可能看不到所有的緩存,而是只能看到其中的一部分。當終端希望通過哈希過程將內容映射到緩存上時,由于不同終端所見的緩存范圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內容被不同的終端映射到不同的緩存區中。這種情況顯然是應該避免的,因為它導致相同內容被存儲到不同緩沖中去,降低了系統存儲的效率。分散性的定義就是上述情況發生的嚴重程度。好的哈希算法應能夠盡量避免不一致的情況發生,也就是盡量降低分散性。
負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容映射到不同的緩沖區中,那么對于一個特定的緩沖區而言,也可能被不同的用戶映射為不同的內容。與分散性一樣,這種情況也是應當避免的,因此好的哈希算法應能夠盡量降低緩沖的負荷。
從表面上看,一致性哈希針對的是分布式緩沖的問題,但是如果將緩沖看作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代表系統內的節點總數)才能到達被查詢的節點。不難想象,當系統規模非常大時,節點數量可能超過百萬,這樣的查詢效率顯然難以滿足使用的需要。換個角度來看,即使用戶能夠忍受漫長的時延,查詢過程中產生的大量消息也會給網絡帶來不必要的負荷。
package heritrix; import java.util.Collection; import java.util.SortedMap; import java.util.TreeMap; public class ConsistentHash<T> { //哈希算法 private final HashFunction hashFunction; //虛擬節點數目 private final int numberOfReplicas; private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>(); public ConsistentHash(HashFunction hashFunction, int numberOfReplicas, Collection<T> nodes){ this.hashFunction = hashFunction; this.numberOfReplicas = numberOfReplicas; for (T node : nodes){ add(node); } } public void add(T node){ for (int i = 0; i < numberOfReplicas; i++){ circle.put(hashFunction.hash(node.toString() + i), node); } } public void remove(T node){ for (int i = 0; i < numberOfReplicas; i++){ circle.remove(hashFunction.hash(node.toString() + i)); } } //關鍵算法 public T get(Object key){ if(circle.isEmpty()){ return null; } //計算hash值 int hash = hashFunction.hash(key); //如果不包括這個hash值 if(!circle.containsKey(hash)){ SortedMap<Integer, T> tailMap = circle.tailMap(hash); hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); } return circle.get(hash); } }
以上是“Java語言Consistent Hash算法怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。