什麼是一致性哈希,和通常的分佈式哈希表(DHT)有什麼區別?通常的DHT使用如下公式進行數據定位:position = Hash(對象名) % N(N是節點個數)。很明顯,若是咱們在集羣中增減一個節點,都必需要從新計算對象的位置,致使大量的數據遷移的發生。文中的對象表示文件(分佈式文件系統)或者數據塊(p2p)。而一致性哈希的計算公式則不一樣:position = Hash(對象名) % M(M是一個常量,通常取2^31 )。git
如何使用一致性哈希定位文件?github
大致上分紅兩步:1. 計算節點位置 2. 將對象分佈到各個節點。下面,我給各位細細道來:golang
開始時咱們使用經常使用的哈希函數以節點名或者節點IP爲鍵值計算哈希並將計算獲得的哈希和M=2^31取模,獲得一個新的哈希值。這個哈希值就表示節點的位置。以下圖所示咱們以節點名做爲鍵值,計算出N1, N2, N3, N4四個節點的哈希分別是2000, 3000, 4000, 5000。算法
隨後,咱們使用相同的方法計算對象的哈希值,hash = Hash(對象名) % (2^31)。計算完成以後獲得對象O1的哈希時2100,這時咱們以順時針的順序將O1放到節點N2。一樣哈希值爲3200的O2被放到節點N3。swift
那麼這樣究竟有什麼好處呢?假如咱們增長一個節點X,計算出來X節點的位置是3500。在普通的DHT中咱們須要從新計算每一個節點中的數據的位置。可是(重點來了)在一致性哈希中,咱們只須要把節點N3中的對象O2遷移到新節點X中。隻影響到節點N3到節點X之間的對象,圖中用黑色粗體標註的部分。大大減小了被影響的節點。負載均衡
咱們在看看刪除節點的狀況,假如咱們刪除節點N3。只須要按照順時針的方向,將N3中的全部對象遷移到離其最近的節點N4。分佈式
能夠看到做爲一種分佈式環境下的數據分佈手段,一致性哈希即保留了DHT的負載均衡的特色,又下降了節點的橫向拓展帶來的數據遷移的開銷。那麼哪裏都用到了一致性哈希?目前我知道的領域有BT下載,分佈式文件系統(IPFS,ceph,openstack swift)。函數
從上面的內容咱們能夠看到,當咱們在增長或者刪除一個節點時,會增長其相鄰節點的負載,這固然不是咱們想看到的,理想的狀態是將負載均衡到集羣中的每個節點。那麼應該怎麼才能作到這一點呢?能夠經過引入虛擬節點來解決這個問題。post
每一個物理節點都被分割爲幾個虛擬節點,每一個對象先計算其位於哪個虛擬節點,在經過判斷虛擬節點的owner,將對象存儲到實際的物理節點。spa
從上圖能夠看到,整個結構分紅兩層,外層的虛擬節點層和內層的物理節點層,而且外層的虛擬節點是隨機分佈的。虛擬節點經過這種隨機的排列順序進一步提升了物理節點的負載均衡。
咱們來看看去掉N4節點時的數據遷移狀況。當移除N4節點時,全部屬於N4的虛擬節點上的數據都要遷移到它們的順時針方向的下一個虛擬節點,本例中是N3#1,N2#2,N1#3,N1#1。能夠看到N4的數據會均衡的再分佈到其他的每個節點。
代碼已經放到github,使用golang來編寫,目前還沒有完成,歡迎你們指正。https://github.com/DennisWong/ConsistentHash.git
一致性Hash(Consistent Hashing)原理剖析,關於虛擬節點的解釋很易懂
https://blog.csdn.net/lihao21/article/details/54193868
五分鐘看懂一致性哈希算法
http://www.javashuo.com/article/p-azvvvvyo-cc.html
介紹openstack的一致性哈希