「nginx
孤單的人啊孤單的歌c++
孤單的時候別唱情歌面試
寫歌的人寫着他的寂寞算法
不必定和你適合數據庫
悲傷的人啊悲傷的歌緩存
悲傷的劇情不一樣角色服務器
編劇的人編着誰的快樂網絡
何須演的那麼深入負載均衡
都是平凡的人分佈式
不是仙也不是神
不悲不喜
該得不可得
愛過的疼過的好聚又好散的
幻想中苦笑不得
不悲不喜該得不可得
見過的路過的獲得又失去的
虛幻中成瘋成魔
」
在敲代碼的時候,來一首寂寞的歌,無限循環中,多了些不同的滋味。
以前,咱們聊過度布式系統設計實踐,詳細的能夠查看一下以前的原創發文。其中,提到了分佈式系統設計實踐中經常使用的算法,一致性Hash算法。並無細緻的對其作講解,今天碰巧遇到小夥伴問,那麼把這個說一下。
一致性哈希算法,是一種分佈式哈希(DHT)算法,主要解決了分佈式哈希的單調性和分散性問題。
單調性,指的要對已經存在的內容可以正常映射,避免在節點增減過程當中,沒法命中,相似於上文說的哈希取模分配,若是幾點不斷增長,計算方式就會失去平衡。分散性,指的就是解決哈希取模分配的不平衡問題。
一致性哈希的論文發表於1997年,閱讀無障礙的同窗能夠直接看看大佬的論文理解更深入,附上論文下載連接:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.147.1879
既然咱們要聊一致性Hash,首先要把Hash這個基礎概念理解透徹、弄明白。
哈希(Hash)是最多見的數據分佈形式。
常見的哈希算法有MD五、CRC 、MurmurHash 等算法,簡單介紹一下。
MD5消息摘要算法(MD5 Message-Digest Algorithm),一種被普遍使用的密碼散列函數,能夠產生出一個128位(16字節)的散列值(hash value),MD5算法將數據(如一段文字)運算變爲另外一固定長度值,是散列算法的基礎原理。由美國密碼學家 Ronald Linn Rivest設計,於1992年公開並在 RFC 1321 中被加以規範。
循環冗餘校驗(Cyclic Redundancy Check)是一種根據網絡數據包或電腦文件等數據,產生簡短固定位數校驗碼的一種散列函數,由 W. Wesley Peterson 於1961年發表。生成的數字在傳輸或者存儲以前計算出來而且附加到數據後面,而後接收方進行檢驗肯定數據是否發生變化。因爲本函數易於用二進制的電腦硬件使用、容易進行數學分析而且尤爲善於檢測傳輸通道干擾引發的錯誤,所以得到普遍應用。
MurmurHash 是一種非加密型哈希函數,適用於通常的哈希檢索操做。由 Austin Appleby 在2008年發明,並出現了多個變種,與其它流行的哈希函數相比,對於規律性較強的鍵,MurmurHash的隨機分佈特徵表現更良好。
這個算法已經被不少開源項目使用,好比libstdc++ (4.6版)、Perl、nginx (不早於1.0.1版)、Rubinius、 libmemcached、maatkit、Hadoop等。
哈希(Hash)實現方式是經過散列方法,經過計算,就能夠映射數據和處理節點關係。
常見的散列方法以下:
場景:
在分佈式系統環境下,數據庫採用了水平分庫,不一樣機器上安裝了相同的庫。那麼,該如何選擇哪一個機器節點進行增刪改查?
很明顯,咱們如何選擇節點,就是須要選擇一個合適的方式進行負載均衡。假使咱們採用普通的hash算法進行負載均衡,並選擇簡單的「取模法」來講明這個過程。
假設有 3 個服務器節點編號 [0 - 2],6 次動做編號 [1 - 6],則完成哈希映射以後,三個節點數據映射狀況以下:
哈希計算公式:動做% 節點總數 = Hash節點下標
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
經過Hash取模法,每一個動做都均勻的分散到了三個不一樣的服務器節點上,看起來很完美!
可是,在分佈式集羣系統的負載均衡實現上,這種模型有兩個問題:
在彈性伸縮的性能要求下,服務節點常常須要擴容縮容。
節點變化使原來計算的哈希值不許確,爲了達到負載均衡的效果,要從新計算並更新哈希值,對於更新後哈希值不一致的原動做歸屬,要遷移到更新後的節點上去。
假設新增了 1 個服務器節點,由原來的 3 個服務節點變成 4 個節點編號 [0 - 3],哈希映射狀況以下:
哈希計算公式:動做% 節點總數 = Hash節點下標
1 % 4 = 1
2 % 4 = 2
3 % 4 = 3
4 % 4 = 0
5 % 4 = 1
6 % 4 = 2
能夠看到後面三個 :四、五、6 對應的存儲節點所有失效了,這就須要把這幾個節點的緩存數據遷移到更新後的節點上 (費時費力) ,也就是由原來的節點 [1, 2, 0] 遷移到節點 [0, 1, 2],遷移後存儲示意圖以下:
線上環境服務節點雖然有各類高可用性保證,但仍是是有宕機的可能,即便沒有宕機也有縮容的需求。無論是宕機和縮容均可以歸結爲服務節點刪除的狀況,下面分析下服務節點刪除對負載均衡哈希值的影響。
同理,面對服務器節點減小,仍要面對Hash從新計算,數據遷移的問題。
普通哈希算法實現的負載均衡各類各樣的實際問題,因此咱們引入一致性哈希算法。
一致性哈希,哈希函數計算方法不變,經過構建環狀的 Hash 空間替代了原來普通的線性 Hash 空間。
哈希環,是一個足夠大的Hash空間(通常是 0 ~ 2^32)
哈希環構建完畢,咱們能夠根據上邊的場景採用一致性Hash形式,進行優化。
能夠用服務器的 IP 或 主機名計算獲得哈希值,計算獲得的哈希值就是服務節點放置在 Hash 環上。
最後,對每一個操做一樣也計算一次哈希值,計算以後的哈希也映射到環上,沿順時針的方向找到的環上的第一個節點。下圖舉例展現了節點的選擇狀況。
相較普通的Hash方式,擴展能力獲得了必定提高。那麼,一致性哈希是如何解決這個問題的呢?
咱們看一下,以下圖所示,當服務器集羣要新增一個節點時,會發生什麼。受影響的只有動做3,原本3是在ip:0,如今移到ip:3上 便可,其他節點存儲的數據保持不動。
普通哈希算法當某一服務節點宕機下線,也會致使原來哈希映射的大面積失效,失效的映射觸發數據遷移影響服務性能,容錯能力不足。一塊兒來看下一致性哈希是如何提高容錯能力的。
以下圖所示,假設一個節點宕機下線,則只需按順時針方向選擇新的節點存放便可,不會對其餘節點數據產生影響。一致性哈希能把節點宕機形成的影響控制在順時針相鄰節點之間,避免對整個集羣形成影響。
上邊咱們介紹了一致性哈希如何解決普通哈希的擴展和容錯問題,原理比較簡單,在理想狀況下能夠良好運行,但在實際使用中還有一些實際問題須要考慮,下面具體分析。
哈希環的空間很大,若是節點比較少,這會致使什麼問題呢?
可能的一種狀況是,較少的服務節點哈希值彙集在一塊兒,好比下圖所示這種狀況,數據按順時針尋找節點就致使全都存儲到一個節點上去,給單個節點很大的壓力!這種狀況稱爲數據傾斜。
一致性哈希-數據傾斜
數據傾斜和節點宕機均可能會致使緩存雪崩。
數據傾斜致使全部數據都打到 單個節點上面,有可能會致使被壓垮,節點宕機,數據又都打到 另外一個節點上面,以後又進行傳遞。這時候故障就像像雪崩時滾雪球同樣越滾越大。
還有一種狀況是節點因爲各類緣由宕機下線。 在數據量特別大的狀況下也可能致使節點雪崩。
總之,連鎖反應致使的整個緩存集羣不可用,就稱爲節點雪崩。
一致性Hash,經過建立「虛擬節點」的方式解決。
以前咱們說,一致性Hash解決了單調性、分散性。其中關鍵的一個技術就是虛擬節點。
所謂虛擬節點,就是對原來單一的物理節點在哈希環上虛擬出幾個它的分身節點,這些分身節點稱爲「虛擬節點」。打到分身節點上的數據實際上也是映射到分身對應的物理節點上,這樣一個物理節點能夠經過虛擬節點的方式均勻分散在哈希環的各個部分,解決了數據傾斜問題。
因爲虛擬節點分散在哈希環各個部分,當某個節點宕機下線,他所存儲的數據會被均勻分配給其餘各個節點,避免對單一節點突發壓力致使的節點雪崩問題。
下圖展現了虛擬節點的哈希環分佈,其中左邊是沒作虛擬節點狀況下的節點分佈,右側是完成虛擬節點配置的節點分佈
一致性哈希-虛擬節點
嗖嗖嗖,高大上的算法,實現起來,真的也就那麼一回事。特別是在面試中,不少時候,面試官的刁難從一致性Hash開始。那麼,相信,今天咱們聊完,已經對一致性hash有深刻理解了,來來來,吊打面試官吧!!
繼續聽歌!