當服務器不多,並且不考慮擴容的時候,可直接使用簡單的路由算法,用服務器數除緩存數據KEY的hash值,余數作為服務器下標即可。
但是當業務發展,網站緩存服務需要擴容時就會出現問題,比如3台緩存服務器要擴容到4台,就會導致75%的數據無法命中,當100台服務器中增加一台,不命中率會到達99%(n/(n+1)),這顯然是不能接受的。
在設計分布式緩存集群的時候,需要考慮集群的伸縮性,也就是當向集群中增加服務器的時候,要盡量減小對集群的影響,而一致性hash算法就是用來解決集群伸縮性。
一致性hash算法通過構造一個長度為2^32的整數環,根據節點名的hash值將緩存服務器節點放置在這個環上,然后計算要緩存的數據的key的hash值,順時針找到最近的服務器節點,將數據放到該服務器上。
有Node0,Node1,Node2三個節點,假設Node0的hash值是1024,key1的hash值是500,key1在環上順時針查找,最近的節點就是Node0。
當服務器集群又開始擴容,新增了Node3節點,從三個節點擴容到了四個節點。
Node3加到了Node2和Node1之間,除了Node2到Node3之間原本是Node1的數據無法再命中,其它的數據不受影響,3台擴容到4台可命中率高達75%,
而且集群越大,影響越小,100台服務器增加一台,命中率可達到99%。
查找不小於查找樹的最小值是用的二叉查找樹實現的。
但是這樣子還是會存在一個問題,就是負載不均衡的問題,當Node3加到Node2和Node1之間時,原本會訪問Node1的緩存數據有50%的概率會緩存到Node3上了,這樣Node0和Node2的負載會是Node1和Node3的兩倍。
要解決一致性hash算法帶來的負載不均衡問題,可通過將每台物理服務器虛擬成一組虛擬緩存服務器,將虛擬服務器的hash值放置在hash環上,KEY在環上先找到虛擬服務器節點,然后再映射到實際的服務器上。
這樣在Node0,1,2虛擬節點都已存在的情況下,將Node3的多個虛擬節點分散到它們中間,多個虛擬的Node3節點會影響到其它的多個虛擬節點,而不是只影響其中一個,這樣將命中率不會有變化,但是負載卻更加均衡了而且虛擬節點越多越均衡。