1. 程式人生 > >一致性Hash介紹及使用場景

一致性Hash介紹及使用場景

個人部落格:www.dutycode.com

公眾號:攀爬蝸牛    或者 dutycode_com 歡迎關注


場景

單個節點的快取容量達到上限,無法繼續單點增加記憶體,如何解決?

單個節點支撐的QPS達到上限,如何解決? 

初步方案

增加N個快取節點,為了保證快取資料的均勻,一般情況會採用對key值hash,然後取模的方式,然後根據結果,確認資料落到哪臺節點上:如下:

hash(key)%N 

很好,這個的確解決了上面的問題,實現了初步的分散式快取,資料均勻分散到了各個節點上,流量請求也均勻的分散到了各個節點。

但是如果出現以下情況,會帶來什麼問題?

1、某臺伺服器突然宕機。快取伺服器從N變為N-1臺。

2、快取容量達到上限或者請求處理達到上限,需要增加快取伺服器,假定增加1臺,則快取伺服器從N變為N+1

上面的情況帶來的問題:

增加或者刪除快取伺服器的時候,意味著大部分的快取都會失效。這個是比較致命的一點,快取失效,如果業務為快取不命中,查詢DB的話,會導致一瞬間DB的壓力陡增。可能會導致整個服務不可用。 

換種描述方式,我們需要解決怎麼樣的問題?或者需求是怎樣的?

     增刪機器時,希望大部分key依舊在原有的快取伺服器上保持不變。舉例來說:key1,key2,key3原先再Cache1機器上,現在增加一臺快取伺服器,希望key1,key2,key3依舊在Cache1機器上,而不是在Cache2機器上。 

改進方案(一致性Hash)

一致性雜湊演算法的簡單背景介紹 (此段內容來自網路)

一致性雜湊演算法在1997年由麻省理工學院提出的一種分散式雜湊(DHT)實現演算法,設計目標是為了解決因特網中的熱點(Hot spot)問題,初衷和CARP十分類似。一致性雜湊修正了CARP使用的簡單雜湊演算法帶來的問題,使得分散式雜湊(DHT)可以在P2P環境中真正得到應用。 

一致性hash演算法提出了在動態變化的Cache環境中,判定雜湊演算法好壞的四個定義:(來自百度百科

  1. 平衡性(Balance):平衡性是指雜湊的結果能夠儘可能分佈到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。很多雜湊演算法都能夠滿足這一條件。

  2. 單調性(Monotonicity):單調性是指如果已經有一些內容通過雜湊分派到了相應的緩衝中,又有新的緩衝加入到系統中。雜湊的結果應能夠保證原有已分配的內容可以被對映到原有的或者新的緩衝中去,而不會被對映到舊的緩衝集合中的其他緩衝區。 

  3. 分散性(Spread):在分散式環境中,終端有可能看不到所有的緩衝,而是隻能看到其中的一部分。當終端希望通過雜湊過程將內容對映到緩衝上時,由於不同終端所見的緩衝範圍有可能不同,從而導致雜湊的結果不一致,最終的結果是相同的內容被不同的終端對映到不同的緩衝區中。這種情況顯然是應該避免的,因為它導致相同內容被儲存到不同緩衝中去,降低了系統儲存的效率。分散性的定義就是上述情況發生的嚴重程度。好的雜湊演算法應能夠儘量避免不一致的情況發生,也就是儘量降低分散性。 

  4. 負載(Load):負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容對映到不同的緩衝區中,那麼對於一個特定的緩衝區而言,也可能被不同的使用者對映為不同 的內容。與分散性一樣,這種情況也是應當避免的,因此好的雜湊演算法應能夠儘量降低緩衝的負荷。

所以通過上面的定義可以看到,簡單的hash(key)%N的方式,違背了 單調性 的這個原則。原因如上面提到的,增刪機器的時候,原有的快取大部分會失效,也就違背了單調性的原則。

介紹:

    大部分文章都提到環形的hash空間,但是沒有講為什麼是環形的。後面我會聊下我的想法。 

    使用常見的hash演算法可以把一個key值雜湊到一個具有2^32個桶的空間中。也可以理解成,將key值雜湊到 [0, 2^32) 的一個數字空間中。 我們假設這個是個首尾連線的環形空間。如下圖:

blob.png

  假設我們現在有key1,key2,key3,key4 4個key值,我們通過一定的hash演算法,將其對應到上面的環形hash空間中。

   k1=hash(key1);

   k2=hash(key2);

   k3=hash(key3);

   k4=hash(key4);

blob.png

同樣的,假設我們有3臺cache伺服器,把快取伺服器通過hash演算法,加入到上述的環中。一般情況下是根據機器的IP地址或者唯一的計算機別名進行雜湊。

c1=hash(cache1);

c2=hash(cache2);

c3=hash(cache3);

blob.png

接下來就是資料如何儲存到cache伺服器上了,key值雜湊之後的結果順時針找上述環形hash空間中,距離自己最近的機器節點,然後將資料儲存到上面, 如上圖所示,k1 儲存到 c3 伺服器上, k4,k3儲存到c1伺服器上, k2儲存在c2伺服器上。用圖表示如下:

blob.png

增刪機器的情況

假設cache3伺服器宕機,這時候需要從叢集中將其摘除。那麼,之前儲存再c3上的k1,將會順時針尋找距離它最近的一個節點,也就是c1節點,這樣,k1就會儲存到c1上了,看一看下下面的圖,比較清晰。

blob.png

摘除c3節點之後,隻影響到了原先儲存再c3上的k1,而k3、k4、k2都沒有受到影響,也就意味著解決了最開始的解決方案(hash(key)%N)中可能帶來的雪崩問題。

增加節點原理和刪除時差不多~

blob.png

新增C4節點之後,原先儲存到C1的k4,遷移到了C4,分擔了C1上的儲存壓力和流量壓力。

幾個問題:

1、為什麼需要想象成環形?

    為了保證節點宕機摘除之後,原先儲存在當前節點的key能找到可儲存的位置。舉個極端的例子,在不是環狀hash空間下,剛好快取的伺服器處於0這個位置,那麼0之後是沒有任何節點資訊的,那麼當快取伺服器摘除的時候,以前儲存在這臺機器上的key便找不到順時針距離它最近的一個節點了。但如果是環形空間,0之後的最近的一個節點資訊有可能是2^32-1這個位置,他可以找到0之後的節點。如下圖描述可能清晰一點。

blob.png

2、為什麼是2^32個桶空間?

  沒有搞清楚,個人理解是為了保證足夠的靈活性,減少hash帶來的key值衝突。也方便後續增刪節點。 

繼續改進

上面的簡單的一致性hash的方案在某些情況下但依舊存在問題:一個節點宕機之後,資料需要落到距離他最近的節點上,會導致下個節點的壓力突然增大,可能導致雪崩,整個服務掛掉。

如下圖所示,

blob.png

當節點C3摘除之後,之前再C3上的k1就要遷移到C1上,這時候帶來了兩部分的壓力:

     1)、之前請求到C3上的流量轉嫁到了C1上,會導致C1的流量增加,如果之前C3上存在熱點資料,則可能導致C1扛不住壓力掛掉。

     2)、之前儲存到C3上的key值轉義到了C1,會導致C1的內容佔用量增加,可能存在瓶頸。

當上面兩個壓力發生的時候,可能導致C1節點也宕機了。那麼壓力便會傳遞到C2上,又出現了類似滾雪球的情況,服務壓力出現了雪崩,導致整個服務不可用。

如果解決上面的問題?

虛擬節點。歪果人的腦子真好使,想出這麼一個牛逼的方式,虛擬節點。

如上描述,一個節點宕機之後可能會引起下個節點的儲存及流量壓力變大,這一點違背了最開始提到的四個原則中的 平衡性, 節點宕機之後,流量及記憶體的分配方式打破了原有的平衡。

虛擬節點,從名字可以看出來,這個節點是個虛擬的,每個實際節點對應多個虛擬節點。比較專業的說法如下:

“虛擬節點”( virtual node )是實際節點(機器)在 hash 空間的複製品( replica ),一實際個節點(機器)對應了若干個“虛擬節點”,這個對應個數也成為“複製個數”,“虛擬節點”在 hash 空間中以hash值排列。

依舊用圖片來解釋,假設存在以下的真實節點和虛擬節點的對應關係。

Visual100—> Real1

Visual101—> Real1

Visual200—> Real2

Visual201—> Real2

Visual300—> Real3

Visual301—> Real3

同樣的,hash之後的結果如下:

hash(Visual100)—> V100  —> Real1

hash(Visual101)—> V101  —> Real1

hash(Visual200)—> V200  —> Real2

hash(Visual201)—> V201  —> Real2

hash(Visual300)—> V300  —> Real3

hash(Visual301)—> V301  —> Real3

key值的hash結果如上,這裡暫時不寫了。

如圖解釋:

blob.png

和之前介紹的不新增虛擬節點的類似,主要聊下如果宕機之後的情況。 

假設Real1機器宕機,則會發生一下情況。

1、原先儲存在虛擬節點V100上的k1資料將遷移到V301上,也就意味著遷移到了Real3機器上。 

2、原先儲存再虛擬節點V101上的k4資料將遷移到V200上,也就意味著遷移到了Real2機器上。

結果如下圖:

12160867-2438-46F8-B74E-0B8E21F32187.png

這個就解決之前的問題了,某個節點宕機之後,儲存及流量壓力並沒有全部轉移到某臺機器上,而是分散到了多臺節點上。解決了節點宕機可能存在的雪崩問題。

當物理節點多的時候,虛擬節點多,這個的雪崩可能就越小。

PS:只有2個節點的時候,加入虛擬節點沒有用。你懂的。 

公眾號:掃一掃關注~~