一致性雜湊演算法是為了解決普通雜湊演算法的熱點問題,當使用普通雜湊演算法來切割資料到不同的快取伺服器時。
一旦快取伺服器的數量產生變化,客戶端向快取伺服器請求相應的資料就不會命中,轉而請求具體的資料庫伺服器,從而造成快取擊穿。
下面我們來看一下使用普通雜湊演算法時所帶來的問題,假如我們擁有 10 臺快取伺服器,那麼我們在存放資料的時候可以對快取資料項的 key 進行雜湊操作,取得其雜湊值,並將其與伺服器數量進行取模運算,就可以得到乙個伺服器下標的數字。
伺服器資訊 = hash(key) % 10
例如我針對字串 "140" 進行 sha256 雜湊操作,得到 762818267,對 10 取模運算結果是 7 號伺服器。但如果增加了一台伺服器,那麼就會變成對 11 取模,,其結果就是 2 號伺服器,得到的位置完全不正確,造成取快取的時候肯定不會命中。
注意:由於畫圖的時候粗心將伺服器 c 的 ip 位址寫成了1.建立乙個環,這個雜湊環有 2^32 個節點。192.168.100.102
,其真實 ip 應該是192.168.100.103
,閱讀文章的時候請注意這個區別。
2.求出伺服器的雜湊值,並將其與雜湊環節點的數量取模,得到的值即是伺服器節點在雜湊環上的位置。
3.根據要儲存的資料項鍵值,求出其雜湊值,與雜湊環節點數量取模,得到在雜湊環的位置。
4.根據資料項在雜湊環的位置,順時針查詢遇到的第乙個伺服器節點,將資料項存放到該伺服器。
5.如果增加了一台伺服器 d,只會影響 d 之前區間的資料。
上述情況僅適用於服務節點在雜湊環上分布均勻的情況,如果雜湊環上伺服器節點的分布位置不均勻,則會導致某個區間內的資料項的大量資料存放在乙個伺服器節點中。如下圖,a 快取伺服器就會接收大量請求,當該伺服器崩潰掉之後,b 伺服器,c 伺服器會依次崩潰,這樣就會造成伺服器雪崩效應,整個快取伺服器集群都會癱瘓。
這種時候,我們可以引入虛擬節點來解決該問題。例如我們擁有 a、b、c 三颱伺服器,我們在雜湊環上建立雜湊伺服器的時候,可以為其建立 n 個虛擬節點,這些虛擬節點都是指向真實伺服器的 ip,這樣我們在雜湊環上的伺服器節點分布就會很均勻。
在這裡我們基於 c# 與 .net core 編寫乙個 demo **,用來演示上述情況,這裡的**僅作演示使用,如果要應用到生產環境,請注意執行緒同步問題。
using system;
using system.collections.generic;
using system.security.cryptography;
using system.text;
/* * 一致性雜湊演算法的 demo,主要用於演示一致性雜湊演算法的實現與實際應用。
*/namespace consistenthashing.startup
}public class virtualnodeinfo
public nodeinfo realnodeinfo
}public class consistenthashing
public nodeinfo getnode(string key)
/// /// 向雜湊環上新增虛擬節點。
///
public void addnode(nodeinfo info)
#";var hashindex = math.abs(getstandardhashcode(virtualnodename) % _ringcount);
// 搜尋空的雜湊環位置
var emptyindex = getemptynodeindex(hashindex);
if (emptyindex == -1)
hashring[emptyindex] = new virtualnodeinfo;}}
public void removenode(nodeinfo info)
#");
}for (int i = 0; i < hashring.length; i++)
}/// /// 計算指定 key 的 hash 值
///
private int getstandardhashcode(string key)
/// /// 迴圈遍歷雜湊環,尋找空節點的索引,防止覆蓋存在的節點資訊。
///
private int getemptynodeindex(int startfindindex)
var nextindex = getnextnodeindex(startfindindex);
// 說明已經遍歷了整個雜湊環,說明沒有空的節點了。
if (startfindindex == nextindex)
startfindindex = nextindex;}}
/// /// 根據指定的索引,獲得雜湊環的下乙個索引。這裡需要注意的是,因為雜湊環是乙個環形,當
/// 當前位置為環的末尾時,應該從 0 開始查詢。
///
private int getnextnodeindex(int preindex)
private virtualnodeinfo getfirstnodeinfo(int currentindex)
return nodeinfo;}}
internal class program
);consistenthashing.addnode(new nodeinfo );
consistenthashing.addnode(new nodeinfo );
consistenthashing.addnode(new nodeinfo );
foreach (var node in consistenthashing.hashring)
// 存放 id 為 15 的快取伺服器
var nodeinfo = consistenthashing.getnode("15");
// 刪除節點測試
consistenthashing.removenode(new nodeinfo );}}
}
一致性雜湊演算法
好吧,我們決定打破這種基於資料項商業邏輯的劃分思維,來考慮一種基於 key 的劃分方式,這有些類似於後面介紹的資料庫水平分割槽 sharding 我們需要設計一種不依賴資料項內容的雜湊演算法,將所有資料項的 key 均衡分配在這三颱快取伺服器上。乙個簡單而有效的方法是 取餘 運算,這就像打撲克時的發...
一致性雜湊演算法
在分布式系統中,如果某業務可以由多個相同的節點處理,很容易想到用hash的方式將業務請求分散到這些節點處理,如果有n個節點,計算方法為 hash id n。如果只是簡單的計算,不涉及使用者狀態,這是乙個簡單有效的方案。如果節點的計算涉及使用者狀態,比如維護購物車 memcache快取服務等,好像也沒...
一致性雜湊演算法
判定好壞的四個定義 1 平衡性 balance 平衡性是指雜湊的結果能夠盡可能分布到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。很多雜湊演算法都能夠滿足這一條件。2 單調性 monotonicity 單調性是指如果已經有一些內容通過雜湊分派到了相應的緩衝中,又有新的緩衝加入到系統中。雜湊的...