一致性hash演算法 C 語言實現

2022-02-17 16:27:43 字數 3681 閱讀 7901

在《一致性hash演算法(consistent hashing)》一文中已經介紹了一致性hash的基本原理,本文將會對其具體實現細節進行描述,並用c++語言對一致性hash進行了簡單的實現。

一致性hash演算法實現有兩個關鍵問題需要解決,乙個是用於結點儲存和查詢的資料結構的選擇,另乙個是結點hash演算法的選擇。

首先來談一下一致性hash演算法中用於儲存結點的資料結構。通過了解一致性hash的原理,我們知道結點可以想象為是儲存在乙個環形的資料結構上(如下圖),結點a、b、c、d按hash值在環形分布上是有序的,也就是說結點可以按hash值儲存在乙個有序的佇列裡。如下圖所示,當乙個hash值為-2^20的請求點p查詢路由結點時,一致性hash演算法會按hash值的順時針方向路由到第乙個結點上(b),也就是相當於要在儲存結點的有序結構中,按查詢的key值找到大於key值中的最小的那個結點。因此,我們應該選擇一種資料結構,它應該高效地支援結點頻繁地增刪,也必須具有理想的查詢效率。那麼,紅黑樹可以滿足這些要求。紅黑樹是一顆近似平衡的一顆二叉查詢樹,因為操作比如插入、刪除和查詢某個值的最壞情況時間都要求與樹的高度成比例,這個在高度上的理論上限允許紅黑樹在最壞情況下都是高效的,而不同於普通的二叉查詢樹。 因此,我們選擇使用紅黑樹作為結點的儲存結構,除了需要實現紅黑樹基本的插入、刪除、查詢的基本功能,我們還應該增加另乙個查詢lookup函式,用於查詢大於key中最小的結點。

接下來,我們來說hash演算法的選擇。一致性hash演算法最初提出來,就是為了解決負載均衡的問題。每個實體結點會包含很多虛擬結點,虛擬結點是平衡負載的關鍵。我們希望虛擬結點可以均衡的雜湊在整個「環」上,這樣不僅可以負載到不同hash值的路由請求,還可以當某個結點down掉,原來路由到down掉結點的請求也可以較均衡的路由到其他結點而不會對某個結點造成大量的負載請求。這裡,我們選擇使用md5演算法。通過md5演算法,可以將乙個標示串(用於標示虛擬結點)轉化得到乙個16位元組的字元陣列,再對該陣列進行處理,得到乙個整形的hash值。由於md5具有高度的離散性,所以生成的hash值也會具有很大的離散性,會均衡的雜湊到「環」上。

筆者用c++語言對一致性hash演算法進行了實現,下面我將會描述下一些關鍵細節。

1、首先定義實體結點類、虛擬結點類。乙個實體結點對應多個虛擬結點。

實體結點 cnode_s:

/*實體結點*/

class cnode_s

;

虛擬結點 cvirtualnode_s:虛擬結點有一指標指向實體結點

/*虛擬結點*/

class cvirtualnode_s

;

2、hash演算法具有可選擇性,定義乙個hash演算法介面,方便以後進行其他演算法的擴充套件。

這裡建立md5hash類,並繼承該介面,通過md5演算法求hash值。

類圖:

chashfun介面:

/*定義hash函式類介面,用於計算結點的hash值*/

class chashfun

;

cmd5hashfun 類繼承chashfun介面,實現獲取hash值的gethashval函式:

/*用md5演算法計算結點的hash值,繼承chashfun父類*/

class cmd5hashfun : public chashfun

;long cmd5hashfun::gethashval(const char * instr)

return hash;

}

3、擴充套件紅黑樹結構中的查詢函式,用於查詢紅黑樹中大於key值中最小的結點。

util_rbtree_node_t* util_rbtree_lookup(util_rbtree_t *rbtree, long key)

else if(key > temp->key)

} /* if node==null return the minimum node */

return ((node != null) ? node : util_rbtree_min(rbtree));

} return null;

}

4、建立一致性hash類。使其具有插入、刪除、查詢實體結點的功能。

具體演算法和操作過程已經在**注釋中說明。

class cconhash

;/*輔助函式,虛擬結點轉化為紅黑樹結點*/

util_rbtree_node_t * vnode2rbnode(cvirtualnode_s * vnode);

cconhash::cconhash(chashfun * pfunc)

int cconhash::addnode_s(cnode_s * pnode)

} }return 0;

}int cconhash::delnode_s(cnode_s * pnode)

} }return 0;

}cnode_s * cconhash::lookupnode_s(const char * object)

return null;

}int cconhash::getvnodes()

util_rbtree_node_t * vnode2rbnode(cvirtualnode_s * vnode)

5、建立乙個客戶端類,對一致性hash演算法進行測試。

寫了乙個getip的函式,模擬隨機產生的ip字串。

測試結果截圖:

分析:上面兩幅圖,左邊為原始四個實體結點的路由情況,後面為刪除結點2(node2)之後的路由情況。不難發現,machineb down之後,原先的路由請求,較均衡地負載到了其他機器結點,而且對原先路由到其他結點的請求沒有影響。比如139.149.184.125這個請求仍會路由到machined,並不會因為結點的減少而造成影響。但是,如果是增加實體結點,可能會造成增加前後路由情況不一致的現象,因為路由區間的更加狹小,但是不會有特別大的影響。 另一方面,可以發現實體結點的虛擬結點個數比例分配情況很大程度影響了結點的負載路由情況,比例大致與虛擬結點個數相一致。

總結:

一致性hash演算法 面試必備 一致性hash演算法

最近公司在招人,我們準備的問題中有一道是關於一致性hash演算法的問題,只有一些面試者能夠回答上來,而且答的也不是很全面,有的面試者只是聽說過,有的連聽都沒聽過,下面我把一致性hash演算法整理一下分享給大家 一致性雜湊演算法在1997年由麻省理工學院的karger等人在解決分布式cache中提出的...

一致性hash演算法虛擬節點 一致性hash演算法

hash 演算法也叫做雜湊演算法,他可以讓任意長度的資料m對映成為長度固定的值h。hash演算法的第乙個作用就是資料的快速儲存與查詢。寫過程式的人都知道,基本上主流的程式語言裡面都有個資料結構叫做map dictionary或者 hash table 它是根據key來直接訪問結果的資料結構。key的...

一致性hash演算法

july部落格16章開始 第一題 全排列,輸入乙個字串,列印出該字串中字元的所有排列 1.個人思路 回溯法建立的排序樹 2.july部落格 遞迴實現,依次固定第乙個字母,後面的交換,和上面描述的使用回溯法相似 c stl 演算法 next permutation的思想,關於next permutat...