一致性Hash算法提出了在動態變化的Cache環境中,判定哈希算法好壞的四個定義:
1、平衡性(Balance):平衡性是指哈希的結果能夠盡可能分布在所有的緩沖(Cache)中去,這樣可以使得所有的緩沖空間得到利用。很多哈希算法都能夠滿足這一條件。
2、單調性(Monotonicity):單調性是指如果已經有一些內容通過哈希分派到了相應的緩沖中,又有新的緩沖加入到系統中。哈希的結果應該能夠保證原有已分配的內容可以被映射到原有的或者新的緩沖中去,而不會映射到舊的緩沖集合中的其他緩沖區。
3、分散性(Spread):在分布式環境中,終端有可能看不到所有的緩沖,而只能看到其中的一部分。當終端希望通過哈希過程將內容映射到緩沖上去,由於不同終端所見的緩沖范圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內容被不同的終端映射到不同的緩沖區中。這種情況顯然是應該避免的,因為它導致相同內容被存儲到不同緩沖中去,降低了系統存儲的效率。分散性的定義就是上述情況發生的嚴重程度。好的哈希算法應該能夠盡量避免不一致的情況發生,也就是盡量降低分散性。
4、負載(Load):負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容映射到不同的緩沖區中,那么對於一個特定的緩沖區而言,也可能被不同的用戶映射到不同的內容。與分散性一樣,這種情況也是應當避免的,因此好的哈希算法應能夠盡量降低緩沖的負荷。
在分布式集群中,對機器的添加刪除,或者機器故障后自動脫落集群這些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有機器添加或者刪除后,很多原有的數據就無法找到了,這樣嚴重的違反了單調性原則。
解釋使用hash(object)%N,其中N是指N個cache服務器/N個節點為啥不行:
如果N個cache服務器中編號為a的服務器故障了,需要把a從服務器群中移除,這個時候cache服務器的數量就變成了N-1台,那么所有對象(object)映射到cache服務器的計算公式就變成了hash(object)%N-1,對,影響到了所有的對象與cache服務器的映射關系,類似,由於訪問加重,需要添加cache服務器,這時候cache服務器是N+1台,映射公式就變成了hash(object)%N+1,這就意味着幾乎所有的cache都失效了,對於服務器而言,這是一場災難,所有訪問都會直接沖向后台服務器。
接下來主要講解一下哈希算法是如何設計的:
環形Hash空間
按照常用的hash算法來將對應的key哈希到一個具有2^32次方個桶的空間中,即0~(2^32)-1的數字空間。現在我們可以將這些數字頭尾相連,想象成一個閉合的環形。如下圖
把數據(對象)通過一定的hash算法處理后映射到環上
現在我們將object1、object2、object3、object4四個對象通過特定的Hash函數計算出對應的key值,然后散列到hash換上。如下圖:
Hash(object1)=key1;Hash(object2)=key2;Hash(object3)=key3;Hash(object4)=key4;
將機器通過hash算法映射到環上
在采用一致性哈希算法的分布式集群中將新的機器加入,其原理是通過使用與對象存儲一樣的Hash算法將機器也映射到換種(一般情況下對機器的hash計算是采用機器的IP或者唯一的別名作為輸入值),然后以順時針的方向計算,將所有對象存儲到離自己最近的機器中。
假設現在有NODE1,NODE2,NODE3三台機器中,通過hash算法得到對應的KEY值,映射到環中,其示意圖如下:
Hash(NODE1)=KEY1;Hash(NODE2)=KEY2;Hash(NODE3)=KEY3;
通過上圖可以看出對象與機器處於同一個哈希空間中,這樣按順時針轉動object1(對象)存儲到了NODE1(機器)中,object3(對象)存儲到了NODE2(機器)中,object2、object4(對象)存儲到了NODE3(機器)中。在這樣的部署環境中,hash環是不會變更的,因此,通過算出對象的hash值就能快速的定位到對應的機器中,這樣就能找到對象真正的存儲位置了。
機器刪除與添加
普通hash求余算法最為不妥的地方就是在有機器的添加與刪除以后會造成大量的對象存儲位置的失效,這樣就大大的不滿足單調性了。下面來分析一下一致性哈希算法是如何處理的。
1、節點(機器)的刪除
以上面的分布式集群為例,如果NODE2出現故障被刪除了,那么按照順時針遷移的方法,object3將會被遷移到NODE3中,這樣僅僅是object3的映射位置發生了變化,其他的對象沒有任何的變動,如下圖:
2、節點(機器)的添加
如果往集群中添加一個新的節點NODE4,通過對應的Hash算法得到KEY4,並映射到環中,如下圖:
通過按照順時針遷移的規則,那么object2被遷移到NODE4中,其他對象還保持這原有的存儲位置。通過對節點的添加和刪除的分析,一致性哈希算法在保持了單調性的同時,還是數據的遷移達到了最小,這樣的算法對分布式集群來說非常合適的,避免了大量收數據遷移,減少了服務器的壓力。
平衡性
根據上面的圖解分析,一致性哈希算法滿足了單調性和負載均衡的特性以及一般hash算法的分散性,但這還並不能當做其被廣泛應用的原由,因為缺少了平衡性。下面將分析一致性哈希算法是如何滿足平衡性的。hash算法是不保證平衡性的,如上面只部署了NODE1和NODE3的情況(NODE2被刪除的圖),object1存儲在NODE1中,而object2、object3、object4都存儲在NODE3中,這樣就造成了非常不平衡的狀態。在一致性哈希算法中,為了盡可能的滿足平衡性,其引入了虛擬節點。
何為虛擬節點?虛擬節點(Virtual node)是實際節點(機器)在hash空間的復制品(replica),一個實際節點對應了若干個“虛擬節點”,這個對應個數也稱為“復制個數”,“虛擬節點”在hash空間中以hash值排列。
在上面只部署了NODE1和NODE3的情況(NODE2被刪除的圖)為例,之前的對象在機器上的分布很不均衡,現在我們以2個副本(每個節點復制2個)為例,這樣整個hash環就存在4個虛擬節點,最后對象映射的關系圖如下:
根據上圖可知對象的映射關系:object1->NODE1-1,object2->NODE1-2 ,object3->NODE3-2,object4->NODE3-1,通過虛擬節點的引入,對象的分布就比較均衡了。那么在實際操作中,真正的對象查詢是如何工作的呢?對象從hash到虛擬節點到實際節點的轉換如下圖:
虛擬節點”的hash計算可以采用對應節點的IP地址加數字后綴的方式。例如假設NODE1的IP地址為192.168.1.100。引入“虛擬節點”前,計算 cache A 的 hash 值:
Hash(“192.168.1.100”);
引入“虛擬節點”后,計算“虛擬節”點NODE1-1和NODE1-2的hash值:
Hash(“192.168.1.100#1”); // NODE1-1
Hash(“192.168.1.100#2”); // NODE1-2
原文:https://blog.csdn.net/cb_lcl/article/details/81448570