????緩存已經成為網站數據服務的重要組成部分回俐,事實上承擔了業(yè)務中絕大多數的數據讀取訪問服務麦牺,緩存服務失效可能導致數據庫負載過高而宕機,進而影響網站的可用性昂拂。如果采用緩存服務集群受神,且集群規(guī)模較大,那么單機宕機引起的緩存數據丟失比例和數據庫負載壓力變化都比較小格侯,對整個系統影響也比較小鼻听。
? ??從某種角度上講,集群越大联四,單機影響越小撑碴,因此在系統設計時,應首先盡量采用大規(guī)模集群緩存朝墩。擴大緩存服務器集群的一個簡單手段醉拓,就是整個網站共享同一個分布式緩存集群,并通過邏輯的方式將每個應用的緩存盡量等概率的分布到集群中每一臺服務器上。這樣亿卤,單機緩存服務器失效愤兵,所有應用都會受到影響,但是受影響程度都比較小排吴,邏輯上等于1/N(N為服務器數量)秆乳。
????如何設計緩存映射關系或者說路由算法才能做到近似等概率分布呢,下面介紹一個經典的解決算法:一致性Hash算法傍念。該算法早在 1997 年就在論文 Consistent hashing and random trees 中被提出矫夷,目前在 cache 系統中應用越來越廣泛葛闷;
1.基本場景
????比如你有 N 個 cache 服務器(后面簡稱 cache )憋槐,那么如何將一個對象 object 映射到 N 個 cache 上呢,你很可能會采用類似下面的通用方法計算 object 的 hash 值淑趾,然后均勻的映射到到 N 個 cache 阳仔;
hash(object)%N
????考慮如下的兩種情況;
1)一個 cache 服務器 m down 掉了(在實際應用中必須要考慮這種情況)扣泊,這樣所有映射到 cache m 的對象都會失效近范,怎么辦,需要把 cache m 從 cache 中移除延蟹,這時候 cache 是 N-1 臺评矩,映射公式變成了 hash(object)%(N-1) ;
2)由于訪問加重阱飘,需要添加 cache 斥杜,這時候 cache 是 N+1 臺,映射公式變成了 hash(object)%(N+1) 沥匈;
1) 和 2) 意味著什么蔗喂?這意味著突然之間幾乎所有的 cache 都失效了。對于服務器而言高帖,這是一場災難缰儿,洪水般的訪問都會直接沖向后臺服務器;
????再來考慮第三個問題散址,由于硬件能力越來越強乖阵,你可能想讓后面添加的節(jié)點多做點活,顯然上面的hash 算法也做不到预麸。
???有什么方法可以改變這個狀況呢义起,這就是一致性Hash算法...
2 hash 算法和單調性
????Hash 算法的一個衡量指標是單調性( Monotonicity ),定義如下:
????單調性是指如果已經有一些內容通過哈希分派到了相應的緩沖中师崎,又有新的緩沖加入到系統中默终。哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩沖中去,而不會被映射到舊的緩沖集合中的其他緩沖區(qū)。
????容易看到齐蔽,上面的簡單 hash 算法hash(object)%N 難以滿足單調性要求,而滿足單調性才能更好的適應Cache的彈性伸縮設計两疚。
3 一致性Hash算法基本原理
????一致性Hash算法是一種 hash 算法,簡單的說含滴,在移除/添加一個 cache 時诱渤,它能夠盡可能小的改變已存在 key 映射關系,盡可能的滿足單調性的要求谈况。
????下面就來按照 5 個步驟簡單講講一致性Hash算法的基本原理勺美。
3.1 環(huán)形hash 空間
????考慮通常的 hash 算法都是將 value 映射到一個 32 位的 key 值,也即是0~2^32-1 次方的數值空間碑韵;我們可以將這個空間想象成一個首( 0 )尾( 2^32-1 )相接的圓環(huán)赡茸,如下面圖 1 所示的那樣。
3.2 把對象映射到hash 空間
接下來考慮 4 個對象object1~object4 祝闻,通過 hash 函數計算出的hash 值key 在環(huán)上的分布如圖 2 所示占卧。
hash(object1)= key1;
……
hash(object4)= key4;
3.3 把cache 映射到hash 空間
????一致性Hash算法的基本思想就是將對象和cache 都映射到同一個 hash 數值空間中,并且使用相同的 hash 算法联喘。
????假設當前有 A,B 和 C 共 3 臺 cache 华蜒,那么其映射結果將如圖 3 所示,他們在 hash 空間中豁遭,以對應的 hash 值排列叭喜。
hash(cacheA) = key A;
……
hash(cacheC) = key C;
????說到這里,順便提一下 cache 的hash 計算蓖谢,一般的方法可以使用 cache 機器的 IP 地址或者機器名作為 hash 輸入捂蕴,評估Hash效果的關鍵是分布是否均勻。
3.4 把對象映射到cache
????現在 cache 和對象都已經通過同一個hash 算法映射到 hash 數值空間中了蜈抓,接下來要考慮的就是如何將對象映射到 cache 上面了启绰。
????在這個環(huán)形空間中,如果沿著順時針方向從對象的 key 值出發(fā)沟使,直到遇見一個 cache 委可,那么就將該對象存儲在這個 cache 上,因為對象和 cache 的 hash 值是固定的腊嗡,因此這個 cache 必然是唯一和確定的着倾。這樣不就找到了對象和 cache 的映射方法了嗎?燕少!
????依然繼續(xù)上面的例子(參見圖 3 )卡者,那么根據上面的方法,對象 object1 將被存儲到 cache A 上客们; object2 和 object3 對應到 cache C 崇决; object4 對應到 cache B 材诽;
3.5 考察cache 的變動
????前面講過,通過 hash 然后求余的方法帶來的最大問題就在于不能滿足單調性恒傻,當 cache 有所變動時脸侥, cache 會失效,進而對后臺服務器造成巨大的沖擊盈厘,現在就來分析分析 consistent hashing 算法睁枕。
3.5.1 移除cache
????考慮假設 cache B 掛掉了,根據上面講到的映射方法沸手,這時受影響的將僅是那些沿 cache B 逆時針遍歷直到下一個 cache ( cache C )之間的對象外遇,也即是本來映射到 cache B 上的那些對象。
????因此這里僅需要變動對象 object4 契吉,將其重新映射到 cache C 上即可跳仿;參見圖 4 。
3.5.2 添加cache
????再考慮添加一臺新的 cache D 的情況栅隐,假設在這個環(huán)形 hash 空間中塔嬉, cache D 被映射在對象 object2 和 object3 之間玩徊。這時受影響的將僅是那些沿 cache D 逆時針遍歷直到下一個 cache ( cache B )之間的對象(它們是也本來映射到 cache C 上對象的一部分)租悄,將這些對象重新映射到 cache D 上即可。因此這里僅需要變動對象 object2 恩袱,將其重新映射到 cache D 上泣棋;參見圖 5 。
? ? 上述算法目前還有另外一個問題畔塔,就是新加入cache D只是分散了Cache C的壓力潭辈,對于其他節(jié)點沒有影響。這顯然與我們增加Cache的初衷還有差距澈吨,我們希望的是新加入節(jié)點應該能夠減輕現有所有節(jié)點的壓力把敢,這就是Hash算法的另一個指標平衡性,定義如下:
??? 平衡性是指哈希的結果能夠盡可能分布到所有的緩沖中去谅辣,這樣可以使得所有的緩沖空間都得到利用修赞。
??? hash算法并不是保證絕對的平衡,如果 cache 較少的話桑阶,對象并不能被均勻的映射到 cache 上柏副,比如在上面的例子中,僅部署 cache A 和 cache C 的情況下蚣录,在 4 個對象中割择, cache A 僅存儲了 object1 ,而 cache C 則存儲了 object2 萎河、 object3 和 object4 荔泳;分布是很不均衡的蕉饼。
??? 怎么辦?
??? 計算機領域有句話:計算機的任何問題都可以通過增加一個虛擬層來解決玛歌。
????為了解決這種情況椎椰, 一致性Hash算法引入了“虛擬節(jié)點”的概念。
4.虛擬節(jié)點
?“虛擬節(jié)點”( virtual node )是實際節(jié)點在 hash 空間的復制品( replica )沾鳄,一實際個節(jié)點對應了若干個“虛擬節(jié)點”慨飘,這個對應個數也成為“復制個數”,“虛擬節(jié)點”在 hash 空間中以 hash 值排列译荞。
??? 總結如下:通過一個物理節(jié)點對應多個虛擬節(jié)點瓤的,然后讓多個虛擬節(jié)點在Hash空間等概率分布。這樣當增加一個物理節(jié)點時吞歼,它可以均勻接收整個Hash空間的數據圈膏。或者說篙骡,實現了增加一個物理節(jié)點稽坤,可以減輕現有所有物理節(jié)點壓力。損壞一個物理節(jié)點糯俗,那么壓力由剩下的全部物理節(jié)點來分擔尿褪。
下面具體介紹:仍以僅部署 cache A 和cache C 的情況為例,在圖 4 中我們已經看到得湘,cache 分布并不均勻≌攘幔現在我們引入虛擬節(jié)點,并設置“復制個數”為 2 淘正,這就意味著一共會存在 4 個“虛擬節(jié)點”摆马, cache A1,
cache A2 代表了 cache A ; cache
C1, cache C2 代表了 cache C 鸿吆;假設一種比較理想的情況囤采,參見圖 6 。
此時惩淳,對象到“虛擬節(jié)點”的映射關系為:
objec1->cache
A2 蕉毯;objec2->cache A1 ; objec3->cache C1 黎泣; objec4->cache C2 恕刘;
因此對象 object1 和 object2都被映射到了 cache A 上,而 object3 和 object4 映射到了 cache C 上抒倚;平衡性有了很大提高褐着。
引入“虛擬節(jié)點”后,映射關系就從 { 對象-> 節(jié)點 } 轉換到了 { 對象 -> 虛擬節(jié)點 } 托呕。查詢物體所在 cache 時的映射關系如圖 7 所示含蓉。
“虛擬節(jié)點”的 hash 計算可以采用對應節(jié)點的 IP 地址加數字后綴的方式频敛。例如假設 cache A 的 IP 地址為 202.168.14.241 。
引入“虛擬節(jié)點”前馅扣,計算 cache A 的 hash 值:
Hash(“202.168.14.241”);
引入“虛擬節(jié)點”后斟赚,計算“虛擬節(jié)”點 cache A1 和 cache A2 的 hash 值:
Hash(“202.168.14.241#1”);?//cache A1
Hash(“202.168.14.241#2”);?//cache A2
5 小結
??? 一致性Hash的核心就是:
(a)一致性Hash空間:保證節(jié)點變化,映射關系大部分不變差油,從而保證大部分數據有效拗军。
(b)虛擬層:保證增加、刪除節(jié)點都是對所有節(jié)點有影響蓄喇,避免不均衡发侵。