常用策略有“求留余數法”和“一致性HASH算法”
redis存儲的是key,value鍵值對
一、求留余數法
使用HASH表數據長度對HASHCODE求余數,余數作為索引,使用該余數,直接設置或訪問緩存。
計算key的HashCode
缺點:增加服務器,由於除數不一樣了,之前緩存的數據都沒辦法訪問了,即不支持熱部署【擴展】
二、一致性HASH算法
一致性HASH算法通過一個叫做一致性HASH環的數據結構,實現KEY到緩存服務器的HASH映射。
算法過程如下:
先構造一個0到232的整數環,然后將服務器節點的Hash值,放在該環上(可以理解為將你的ip做hash,將ip的HashCode放在環上)。然后根據需要緩存的數據的Key,計算Key的HashCode,然后在環上,順時針查找距離這個Key的Hash值最近的緩存服務器的節點,然后將Value,存儲到該服務器節點上。
這是當緩存服務器集群需要擴容的時候,只需要將新加入的節點的HashCode,放入一致性Hash環中,由於Key是順時針查找距離最近的節點,因此,新加入的節點只影響整個環中的一小段。
請參見上圖,如果我們新加入的服務器節點Node3,在Node1和Node2之間,如下圖:
那么受影響的區域,只是Node2到Node3之間(順時針)的緩存,此區間的緩存數據,加入節點之前是緩存在Node1上的,現在需要重新緩存到Node3上面。
具體應用中,這個長度為232的整數環,通常使用二叉查找樹實現,Hash查找過程實際上是在二叉樹中查找不小於查找樹的最小值。當然,這個二叉樹的最右邊的葉子節點和最左邊的葉子節點相連接,構成環。
通過上面的一致性Hash算法,就解決了分布式緩存集群中擴容的問題。然而上面的方法,仍然有問題。我們已經說過,上面的架構,只影響了Node2到Node3之間的區域(順時針),那么Node3,也只是分攤了Node1節點的壓力,而Node0和Node2的訪問壓力,並沒有變化。也就是說:我們加入了硬件投入,卻起到了很小的效果。
一致性Hash算法的進化版
所以說,我們還需要對上面的做法,進行改進。
上述問題是,一致性Hash算法帶來的負載均衡不均衡。我們可以通過增加虛擬層來實現。
我們將每台緩存服務器,虛擬為一組虛擬緩存服務器,將虛擬服務器的Hash值,放置在Hash環上,Key在環上先找到虛擬服務器節點,再得到物理服務器的信息。
這樣,一台服務器節點,被環中多個虛擬節點所代表,且多個節點均勻分配。很顯然,每個物理節點對應的虛擬節點越多,各個物理節點之間的負載越均衡,新加入物理服務器對原有的物理服務器的影響越保持一致。