0x00 摘要
一致性哈希算法是分布式系統中常用的算法。但相信很多朋友都是知其然而不知其所以然。本文將盡量使用易懂的方式介紹一致性哈希原理,並且通過具體應用場景來幫助大家深入這個概念。
0x01. 概念&原理
Hash,一般翻譯做散列、雜湊,或音譯為哈希,是把任意長度的輸入(又叫做預映射pre-image)通過散列算法變換成固定長度的輸出,該輸出就是散列值。
一致性哈希算法在1997年由麻省理工學院的Karger等人在解決分布式Cache中提出的,主要是為了解決因特網中的熱點(Hot spot)問題。目前這一思想已經擴展到其它的領域,並且在實踐中得到了很大的發展。
1. 與經典哈希方法的對比
-
經典哈希方法:總是假設內存位置的數量是已知且固定不變的。因為hash映射依賴節點/內存位置,所以如果需要變化集群,需要重新計算每一個key的哈希值。哈希表(服務器數量)大小的變更實際上干擾了 所有映射。
-
一致性哈希:某種虛擬環結構。位置數量不再固定,環有無限數量的點,服務器節點可以放置在環上的隨機位置。哈希表(服務器數量)大小改變會導致 只有 一部分請求(相對於環分配因子)會受到特定的環變更的影響
2. 通俗理解一致性哈希的關鍵點:
從拗口的技術術語來解釋,一致性哈希的技術關鍵點是:按照常用的hash算法來將對應的key哈希到一個具有2^32次方個桶的空間中,即0 ~(2^32)-1的數字空間。我們可以將這些數字頭尾相連,想象成一個閉合的環形。
用通俗白話來理解,這個關鍵點就是:在部署服務器的時候,服務器的序號空間已經配置成了一個固定的非常大的數字 1~2^32。服務器可以分配為 1~2^32 中任一序號。這樣服務器集群可以固定大多數算法規則 (因為序號空間是算法的重要參數),這樣面對擴容等變化只是對部分算法規則做調整。具體會參見后面實例詳細說明。
3. 一致性哈希如何處理請求
如何決定哪個請求將由哪個服務器節點來處理?
從理論上來說,每個服務器節點“擁有”哈希環的一個區間,進入該區間的任何請求將由同一服務器節點來處理。
4. 異常處理/變化應對
如果其中一個服務器節點出現故障,下一個服務器節點的區間就變寬,進入該區間的任何請求都將進入到新的服務器節點。這時候應該如何處理這些異常的請求?
一致性Hash的優勢就在這里體現:需要重新分配的是僅僅這一個區間(與出現故障的服務器節點對應),哈希環的其余部分和請求/節點分配仍然不受影響。
0x02. 具體應用場景(通過名著水滸傳為例來闡釋)
大家都知道,梁山泊山下有四個酒店。分別是: 東山酒店 / 西山酒店 / 南山酒店 / 北山酒店
那么這四個酒店如何分配客人入住呢? 這里就能用到Hash算法,也能看到一致性哈希的好處。
1. 經典算法:
梁山4個酒店,按照順序其序號是1,2,3,4。
哈希函數:客人姓名筆畫 / 4得到一個余數,客人按照余數分配到這4個酒店中
如果減少一個酒店,哈希函數就變成: 客人按照姓名筆畫 / 3,然后客人按照這個新余數來分配酒店。所有客人都得重新分配酒店
如果增加一個酒店,哈希函數就變成: 客人按照姓名筆畫 / 5,然后客人按照這個新余數來分配酒店。所有客人都得重新分配酒店
可以看到,如果有容量變化,則哈希函數和分配規則都要改變,這樣就對整體機制造成了傷害。
2. 一致性算法:
預先就把服務器的序號空間(現在~未來)想好了,定為100個桶。就是在未來可見的年份內,100個肯定夠了(l梁山無論怎么擴大生產規模,哪怕擴招了10000個頭領,山下也沒有開設100個酒店的可能)。
哈希函數(這個固定不變):
客人姓名筆畫/100. 這個是固定不變的! 因為100這個序號空間固定了,所以哈希函數和分配規則都基本固定了。
酒店/客人分配規則如下(這個會根據容量變化做相應微調):
-
酒店1負責 hash(x)--> 1~20,即客人姓名筆畫/100位於1~20之間。
-
酒店2負責 hash(x)--> 21~40,即客人姓名筆畫/100位於21~40之間。
-
酒店3負責 hash(x)--> 41~60,即客人姓名筆畫/100位於41~60之間。
-
酒店4負責 hash(x)--> 61~100,即客人姓名筆畫/100位於61~100之間。
客人住店規則如下(這個固定不變):
-
客人來了,姓氏筆畫/100,得到余數。去余數對應的酒店住。比如余數3住到酒店1,余數22則住到酒店2......
-
如果該酒店出問題關門了,就去比所有 "比余數大的酒店" 中最小那個住。以此類推。比如酒店1掛了,就去酒店2,酒店2掛了去3。
-
如果最大酒店也出問題關門了,就轉圈回到最小酒店住。即如果酒店4掛了去酒店1.
異常處理(擴容或者宕機):
-
減少酒店。如果酒店3掛了,則原來去酒店3的客人去酒店4,原來去酒店4的客人還是酒店4. 這樣只有酒店4受到影響,1,2號酒店客人不用搬家。
-
增加酒店。如果增加了一個酒店5.則需要對 酒店/客人分配規則 做改變。讓4號酒店負責61~80,5號酒店負責81~100。這樣4號點原有部分客人要遷移到5號。
關鍵點:
可以看出來,關鍵在於服務器的序號空間早就確定了是一個以后也不會修改的大數字100。當然這是梁山。對於其他真實案例可能是2^32。這樣hash函數 (因為序號空間是算法一個重要參數) 可以保持不變,只有"分配規則" 需要根據實際系統容量做相應微調。從而對整體系統影響較小。
當然具體分配酒店的規則算法,是可以融入到hash中。即酒店號碼可能就是21,41,61....
0x03. 參考
https://blog.csdn.net/gerryke/article/details/53939212
https://blog.csdn.net/cb_lcl/article/details/81448570
https://www.iteblog.com/archives/2499.html
http://www.zsythink.net/archives/1182/