1. 程式人生 > >一致性雜湊(Consistent Hashing)原理

一致性雜湊(Consistent Hashing)原理

-轉自【http://afghl.github.io/2016/07/04/consistent-hashing.html】,僅供學習

看一些分散式相關的技術文章或書籍時,經常看到一個詞,一致性雜湊。對於這個技術一直似懂非懂。今天花了半天的時間好好研究了它的原理和實現,發現一點都不復雜。於是寫篇文章分享一下。

下面,我們就從基本的Hash演算法說起。

負載均衡與Hash演算法

分散式系統中(如:web儲存),當服務增長到一定規模時,慣常的做法是叢集化,引入負載均衡,這樣做的好處是:1. 高可用。2. 解耦。從外部看,透明化了叢集的內部細節(外部都通過負載均衡伺服器通訊,然後由負載均衡伺服器分發請求)。

假設一個簡單的場景:有4個cache伺服器(後簡稱cache)組成的叢集,當一個物件object傳入叢集時,這個物件應該儲存在哪一個cache裡呢?一種簡單的方法是使用對映公式:

Hash(object) % 4

這個演算法就可以保證任何object都會盡可能隨機落在其中一個cache中。一切執行正常。

然後考慮以下情況:

  • 由於流量增大,需要增加一臺cache,共5個cache。這時,對映公式就變成Hash(object) % 5
  • 有一個cache伺服器down掉,變成3個cache。這時,對映公式就變成Hash(object) % 3

可見,無論新增還是減少節點,都會改變對映公式,而由於對映公式改變,幾乎所有的object都會被對映到新的cache中,這意味著一時間所有的快取全部失效。 大量的資料請求落在app層甚至是db層上,這對伺服器的影響當然是災難性的。

這時,我們就需要新的演算法。

一致性Hash

一致性hash的出現就是為了解決這個問題:當節點數量改變時,能夠使失效的快取數量儘可能少。

一致性Hash的基本思想就是分兩步走:

  1. 把object求hash(這一步和之前相同);
  2. 把cache也求hash,然後把object和cache的hash值放入一個hash空間,通過一定的規則決定每個object落在哪一個cache中。

下面,會逐步說明它的實現。

成環

考慮通常的Hash演算法都是將value對映到一個32位的key值,也即是0 ~ 2 ^ 32 - 1次方的數值空間;我們可以將這個空間想象成一個首(0)尾(2 ^ 32 - 1)相接的圓環,如下圖所示。

Alt

將object對映到環上

比如有4個需要儲存的object,先求出它們的hash值,根據hash值對映到環上。如圖:

Alt

將cache對映到環上

假設有三臺cache伺服器:cache A,cache B,cache C。用同樣的方法求出hash值(可根據機器的IP或名字作為key求hash,只要保證hash值足夠分散),對映到同一個環上。如圖:

Alt

將object按照規則配對cache

這裡的規則很簡單:讓object在環上順時針轉動,遇到的第一個cache即為對應的cache伺服器。

根據上面的方法,對object1將被儲存到cache A上;object2和object3對應到cache C;object4對應到cache B。

解決問題

新的一致性hash演算法成功解決了cache伺服器增減時key的失效問題。現在,無論增減cache,只有部分key失效

考慮增加新的快取伺服器的情況:

alt

如圖,新增了cache D節點,假設cache D在環上落在C和A之間,那麼失效的只有部分落在cache A的key(現在落在cache D了);也就是部分的紅色圓弧,變成橙色圓弧(D)。

而cache B和cache C的key都沒有失效。

可見,在新增節點時,這已經是最少失效了。

在移除節點時,情況也是和新增節點類似的。

虛擬節點

hash演算法的一個考量指標是平衡性。在本例中,我們希望每一個object落在任意一個cache的機會都儘可能接近。

從圖上很容易直觀的看到,對於一個object來說,它落在環上的任何位置的概率都是一樣的,那麼落在一個cache的概率就和圓弧的長度成正比。於是,我們希望每個cache所佔的圓弧長度更接近。

其實,理論上,只要cache足夠多,每個cache在圓環上就會足夠分散。但是在真實場景裡,cache伺服器只會有很少,所以,引入了“虛擬節點”(virtual node)的概念:

以僅部署cache A和cache C的情況為例,引入虛擬節點,cache A1, cache A2代表了cache A;cache C1,cache C2代表了cache C。

alt

此時,物件到“虛擬節點”的對映關係為:

objec1->cache A2;objec2->cache A1;objec3->cache C1;objec4->cache C2;

因此物件object1和object2都被對映到了cache A上,而object3和object4對映到了cache C上;平衡性有了很大提高。

虛擬節點技術實則是做了兩次matching,如圖:

alt