詳解Consistent Hashing演算法
在做伺服器負載均衡時候可供選擇的負載均衡的演算法有很多,包括: 輪循演算法(Round Robin)、雜湊演算法(HASH)、最少連線演算法(Least Connection)、響應速度演算法(Response Time)、加權法(Weighted )等。其中雜湊演算法是最為常用的演算法.
典型的應用場景是: 有N臺伺服器提供快取服務,需要對伺服器進行負載均衡,將請求平均分發到每臺伺服器上,每臺機器負責1/N的服務。
常用的演算法是對hash結果取餘數 (hash() mod N ):對機器編號從0到N-1,按照自定義的 hash()演算法,對每個請求的hash()值按N取模,得到餘數i,然後將請求分發到編號為i的機器。但這樣的演算法方法存在致命問題,如果某一臺機器當機,那麼應該落在該機器的請求就無法得到正確的處理,這時需要將當掉的伺服器從演算法從去除,此時候會有(N-1)/N的伺服器的快取資料需要重新進行計算;如果新增一臺機器,會有N /(N+1)的伺服器的快取資料需要進行重新計算。對於系統而言,這通常是不可接受的顛簸(因為這意味著大量快取的失效或者資料需要轉移)。那麼,如何設計一個負載均衡策略,使得受到影響的請求儘可能的少呢?
在Memcached、Key-Value Store 、Bittorrent DHT、LVS中都採用了Consistent Hashing演算法,可以說Consistent Hashing 是分散式系統負載均衡的首選演算法。
1、Consistent Hashing演算法描述
下面以Memcached中的Consisten Hashing演算法為例說明(參考memcached的分散式演算法 )。
由於hash演算法結果一般為unsigned int型,因此對於hash函式的結果應該均勻分佈在[0,232 -1]間,如果我們把一個圓環用232 個點來進行均勻切割,首先按照hash(key)函式算出伺服器(節點)的雜湊值, 並將其分佈到0~232 的圓上。
用同樣的hash(key)函式求出需要儲存資料的鍵的雜湊值,並對映到圓上。然後從資料對映到的位置開始順時針查詢,將資料儲存到找到的第一個伺服器(節點)上。
Consistent Hashing原理示意圖
1. 新增一個節點:只有在圓環上新增節點到逆時針方向的第一個節點之間的資料會受到影響(增加節點順時針的第一個節點的資訊需要遷移到增加節點上)。
2. 刪除一個節點:只有在圓環上原來刪除節點到 逆時針 方向的第一個節點之間的資料會受到影響(刪除節點的資訊需要遷移到順時針的第一個節點上) ,因此通過Consistent Hashing很好地解決了負載均衡中由於新增節點、刪除節點引起的hash值顛簸問題。
Consistent Hashing新增伺服器示意圖
虛擬節點(virtual nodes): 之所以要引進虛擬節點是因為在伺服器(節點)數較少的情況下(例如只有3臺伺服器),通過hash(key)算出節點的雜湊值在圓環上並不是均勻分佈的(稀疏的),仍然會出現各節點負載不均衡的問題。虛擬節點可以認為是實際節點的複製品(replicas),本質上與實際節點實際上是一樣的(key並不相同)。引入虛擬節點後,通過將每個實際的伺服器(節點)數按照一定的比例(例如200倍)擴大後並計算其hash(key)值以均勻分佈到圓環上。在進行負載均衡時候,落到虛擬節點的雜湊值實際就落到了實際的節點上。由於所有的實際節點是按照相同的比例複製成虛擬節點的,因此解決了節點數較少的情況下雜湊值在圓環上均勻分佈的問題。
虛擬節點對Consistent Hashing結果的影響
從上圖可以看出,在節點數為10個的情況下,每個實際節點的虛擬節點數為實際節點的100-200倍的時候,結果還是很均衡的。
2、Consistent Hashing演算法實現:
文章Consistent Hashing 中描述了Consistent Hashing的Java實現,很簡潔。
- import java.util.Collection;
- import java.util.SortedMap;
- import java.util.TreeMap;
- public class ConsistentHash<T> {
- private final HashFunction hashFunction;
- private final int numberOfReplicas;
- private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>();
- public ConsistentHash(HashFunction hashFunction, int numberOfReplicas,
- Collection<T> nodes) {
- this.hashFunction = hashFunction;
- this.numberOfReplicas = numberOfReplicas;
- for (T node : nodes) {
- add(node);
- }
- }
- public void add(T node) {
- for (int i = 0; i < numberOfReplicas; i++) {
- circle.put(hashFunction.hash(node.toString() + i), node);
- }
- }
- public void remove(T node) {
- for (int i = 0; i < numberOfReplicas; i++) {
- circle.remove(hashFunction.hash(node.toString() + i));
- }
- }
- public T get(Object key) {
- if (circle.isEmpty()) {
- return null;
- }
- int hash = hashFunction.hash(key);
- if (!circle.containsKey(hash)) {
- SortedMap<Integer, T> tailMap = circle.tailMap(hash);
- hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
- }
- return circle.get(hash);
- }
- }
相關文章
- 一致性 hash 演算法( consistent hashing )演算法
- 一致性雜湊演算法(consistent hashing)【轉】演算法
- 五分鐘理解一致性雜湊演算法(consistent hashing)演算法
- 如何用double hashing解決collision resolution問題
- 詳解BitMap演算法演算法
- BitMap演算法詳解演算法
- Manacher演算法詳解演算法
- KMP演算法詳解KMP演算法
- CTC演算法詳解演算法
- RSA演算法詳解演算法
- consistent gets
- Kd Tree演算法詳解演算法
- Crypto演算法庫詳解演算法
- 演算法 | 快速排序詳解演算法排序
- HOG特徵演算法詳解HOG特徵演算法
- 谷歌PageRank演算法詳解谷歌演算法
- 歸併演算法詳解演算法
- 尋路演算法之A*演算法詳解演算法
- 圖解機器學習 | 降維演算法詳解圖解機器學習演算法
- [譯]實現 Equality 和 Hashing
- 詳解vue的diff演算法Vue演算法
- Paxos共識演算法詳解演算法
- MD5演算法詳解演算法
- Raft共識演算法詳解Raft演算法
- DES演算法例項詳解演算法
- YOLO9000演算法詳解YOLO演算法
- Vue-diff演算法詳解Vue演算法
- 分代收集演算法詳解演算法
- KMP演算法詳解 轉帖KMP演算法
- YOLOP 多工演算法詳解YOLO演算法
- Export Parameter : ConsistentExport
- 什麼BRIEF演算法?BRIEF演算法詳解演算法
- 字串匹配演算法(二)-BM演算法詳解字串匹配演算法
- Deep Hashing Network for Efficient Similarity RetrievalMILA
- Distributed Mutual Exclusion演算法詳解演算法
- 【字串演算法】字典樹詳解字串演算法
- AI美顏SDK演算法詳解AI演算法
- Python遞迴演算法詳解Python遞迴演算法