探索c 之一致性Hash詳解

2021-09-08 10:55:50 字數 3796 閱讀 1903

閱讀目錄:

使用場景

演算法原理

虛擬節點

**示例

以redis為例,當系統需要快取的內容超過單機記憶體大小時,例如要快取100g資料,單機記憶體僅有16g時。這時候就需要考慮進行快取資料分片,也即是把100g的資料拆分成多塊小於單機記憶體的資料。例如以10g為單位,拆分10份,儲存到多台機器節點上。 但是資料怎麼個分法更合理呢? 、

這裡配置n=10,不同的key根據數值餘數對映到對應的機器。 很簡單的辦法就解決了多台節點key分法的問題。然而資料大小的增長和縮減是很難預知的, 如果需要增加一台快取伺服器。 配置n=11,會發現之前根據餘數建立的對映關係發生混亂。對映錯亂後,就會發生大量key無法命中正確的節點,需要全部重新進行對映。  如果以後再新增節點,同樣會遇到這樣問題。 

servers = ['

redis:6379

', '

redis:6380

', '

redis:6381']

server = servers[f(key) % servers.length]

為了降低新增或刪除伺服器節點,導致大量key無法命中的影響。就提出了一種更為合理的分法,也即是一致性hash演算法。 下面看下為什麼更合理些?

我們在腦中假想下:每台節點以chash(ip)形式計算出乙個數值,n臺機器有n個數值。 把數值首尾相連,形成乙個虛擬圓環的數值空間。

例如有3臺機器:

servers =['

redis:6379

', '

redis:6380

', '

redis:6381']。

chash(server[

0])==100

chash(server[

1])==200

chash(server[

2])==300

把機器計算得到的數值,在虛擬圓環中按照順時針方向來確定空間歸屬,得到:

100~200空間屬於6379管。

200~300空間屬於6380管。

300+,100-空間屬於6381管。

這時有3個key要儲存到redis,分別是key1—key3。 通過chash函式計算出3個key的數值座標:

chash(key1)=102

chash(key2)=240

chash(key3)=350

求出key的數值座標後,就知道key與機器節點的對映關係。 即key1應儲存在6379,key3儲存到6381。

由於快取資料的增加,需要新增一台新節點6382。計算出空間數值:

chash(6382)==250
那麼他在虛擬圓環中的位置如下:

從圖中得知,6379、6381的數值空間區域沒任何變化,它們儲存的key依舊可以正常命中的。

優點之一:對現有快取的命中影響較小。

但原本6380的區域200~300被6382侵入了。 6382的空間數值250正好劃分一半,即200~250的區域還歸6380管,但250~300的區域卻歸新來的管了。 (為示例而使用簡單數字區分,實際上沒這麼精準)

優點之二:實現對資料的分片

同時也帶來了缺點就是: 原本儲存在6380(250~300這部分)的舊快取資料就無法命中了,要去新的6382拿。 所以說一致性hash並不能完全解決這種影響,只能盡量降低。

與新增節點同理。比如拿掉新加的6382,250~300區域還管原來的6380管,當然6382這部分快取也就丟了。

一致性hash雖然實現了資料分片,但由於節點較少,key有可能會大量集中到某一台上面,導致快取分布不均勻。 特別是在只有幾台或十幾台機器節點時。

為了降低這種影響,一致性hash演算法提出虛擬節點的解決方案。 即乙個物理機器節點對應著多個虛擬節點。 這裡配置乙個物理節點對應2個虛擬節點,此時應為:

6379=

6380=

6381=

這樣成了6個節點了(可以配置更多),它們同樣在虛擬圓環上按數值順時針排列。由於節點變多,對應的數值區域也變大。使key進行數值空間對映時變的更加離散性,從概率上來提高key的均勻分布。

原本需要計算真實節點數值,也變成計算虛擬節點數值, 然後由虛擬節點的數值構成虛擬圓環數值空間。其中每一組虛擬節點數值,對應單個物理節點。

servers= ['

redis:6379

', '

redis:6380

', '

redis:6381'];

//下面f函式中先將servers與虛擬節點對映成 6379=, 6380=,6381=

// 在對虛擬節點求各自的數值,而數值對應的還是物理節點。即:
vservers = f(servers) =;

chash(key1)==102 ∈ vservers[0] 

......

chash(key3)==350 ∈ vservers[1]

虛擬節點使key分布的更加均衡,但不能解決新增機、刪除節點帶來的影響。

1:使用字典模擬虛擬圓環,並新增節點。

2:計算key數值,應該歸屬到哪個節點數值空間區域。

3:計算分布頻率。複製的虛擬節點越多,分布越平均。

private

static

readonly sorteddictionary _circle = new sorteddictionary();

static

void main(string

args)

var counts = nodes.groupby(n => n, n =>n.count()).tolist();

counts.foreach(index => console.writeline(index.key+"-

"+index.count()));

console.readline();

}

輸出:127.0.0.1:6380-39

127.0.0.1:6381-29

127.0.0.1:6379-32

虛擬圓環的值:

其餘**:

public

static

void addnode(string node, int

repeat)

}public

static

ulong md5hash(string

key)

}public

static

string gettargetnode(string

key)

//////

計算key的數值,得出空間歸屬。

/// ///

//////

public

static

ulong modifiedbinarysearch(ulong sortedarray, ulong

val)

else

}return

sortedarray[max];

}

view code

一致性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...