1. 程式人生 > >一致性雜湊演算法原理及其在分散式系統中的應用

一致性雜湊演算法原理及其在分散式系統中的應用

分散式快取問題

假設我們有一個網站,最近發現隨著流量增加,伺服器壓力越來越大,之前直接讀寫資料庫的方式不太給力了,於是我們想引入Memcached作為快取機制。現在我們一共有三臺機器可以作為Memcached伺服器,如下圖所示。

很顯然,最簡單的策略是將每一次Memcached請求隨機發送到一臺Memcached伺服器,但是這種策略可能會帶來兩個問題:一是同一份資料可能被存在不同的機器上而造成資料冗餘,二是有可能某資料已經被快取但是訪問卻沒有命中,因為無法保證對相同key的所有訪問都被髮送到相同的伺服器。因此,隨機策略無論是時間效率還是空間效率都非常不好。

要解決上述問題只需做到如下一點:保證對相同key的訪問會被髮送到相同的伺服器。很多方法可以實現這一點,最常用的方法是計算雜湊。例如對於每次訪問,可以按如下演算法計算其雜湊值:

h = Hash(key) % 3

其中Hash是一個從字串到正整數的雜湊對映函式。這樣,如果我們將Memcached Server分別編號為0、1、2,那麼就可以根據上式和key計算出伺服器編號h,然後去訪問。

這個方法雖然解決了上面提到的兩個問題,但是存在一些其它的問題。如果將上述方法抽象,可以認為通過:

h = Hash(key) % N

這個算式計算每個key的請求應該被髮送到哪臺伺服器,其中N為伺服器的臺數,並且伺服器按照0 – (N-1)編號。

這個演算法的問題在於容錯性和擴充套件性不好。所謂容錯性是指當系統中某一個或幾個伺服器變得不可用時,整個系統是否可以正確高效執行;而擴充套件性是指當加入新的伺服器後,整個系統是否可以正確高效執行。

現假設有一臺伺服器宕機了,那麼為了填補空缺,要將宕機的伺服器從編號列表中移除,後面的伺服器按順序前移一位並將其編號值減一,此時每個key就要按h = Hash(key) % (N-1)重新計算;同樣,如果新增了一臺伺服器,雖然原有伺服器編號不用改變,但是要按h = Hash(key) % (N+1)重新計算雜湊值。因此係統中一旦有伺服器變更,大量的key會被重定位到不同的伺服器從而造成大量的快取不命中。而這種情況在分散式系統中是非常糟糕的。

一個設計良好的分散式雜湊方案應該具有良好的單調性,即服務節點的增減不會造成大量雜湊重定位。一致性雜湊演算法就是這樣一種雜湊方案。

一致性雜湊演算法

演算法簡述

整個空間按順時針方向組織。0和232-1在零點中方向重合。

下一步將各個伺服器使用H進行一個雜湊,具體可以選擇伺服器的ip或主機名作為關鍵字進行雜湊,這樣每臺機器就能確定其在雜湊環上的位置,這裡假設將上文中三臺伺服器使用ip地址雜湊後在環空間的位置如下:

接下來使用如下演算法定位資料訪問到相應伺服器:將資料key使用相同的函式H計算出雜湊值h,通根據h確定此資料在環上的位置,從此位置沿環順時針“行走”,第一臺遇到的伺服器就是其應該定位到的伺服器。

例如我們有A、B、C、D四個資料物件,經過雜湊計算後,在環空間上的位置如下:

根據一致性雜湊演算法,資料A會被定為到Server 1上,D被定為到Server 3上,而B、C分別被定為到Server 2上。

容錯性與可擴充套件性分析

下面分析一致性雜湊演算法的容錯性和可擴充套件性。現假設Server 3宕機了:

可以看到此時A、C、B不會受到影響,只有D節點被重定位到Server 2。一般的,在一致性雜湊演算法中,如果一臺伺服器不可用,則受影響的資料僅僅是此伺服器到其環空間中前一臺伺服器(即順著逆時針方向行走遇到的第一臺伺服器)之間資料,其它不會受到影響。

下面考慮另外一種情況,如果我們在系統中增加一臺伺服器Memcached Server 4:

此時A、D、C不受影響,只有B需要重定位到新的Server 4。一般的,在一致性雜湊演算法中,如果增加一臺伺服器,則受影響的資料僅僅是新伺服器到其環空間中前一臺伺服器(即順著逆時針方向行走遇到的第一臺伺服器)之間資料,其它不會受到影響。

綜上所述,一致性雜湊演算法對於節點的增減都只需重定位環空間中的一小部分資料,具有較好的容錯性和可擴充套件性。

虛擬節點

一致性雜湊演算法在服務節點太少時,容易因為節點分部不均勻而造成資料傾斜問題。例如我們的系統中有兩臺伺服器,其環分佈如下:

此時必然造成大量資料集中到Server 1上,而只有極少量會定位到Server 2上。為了解決這種資料傾斜問題,一致性雜湊演算法引入了虛擬節點機制,即對每一個服務節點計算多個雜湊,每個計算結果位置都放置一個此服務節點,稱為虛擬節點。具體做法可以在伺服器ip或主機名的後面增加編號來實現。例如上面的情況,我們決定為每臺伺服器計算三個虛擬節點,於是可以分別計算“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”、“Memcached Server 2#1”、“Memcached Server 2#2”、“Memcached Server 2#3”的雜湊值,於是形成六個虛擬節點:

同時資料定位演算法不變,只是多了一步虛擬節點到實際節點的對映,例如定位到“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”三個虛擬節點的資料均定位到Server 1上。這樣就解決了服務節點少時資料傾斜的問題。在實際應用中,通常將虛擬節點數設定為32甚至更大,因此即使很少的服務節點也能做到相對均勻的資料分佈。

總結

轉:http://blog.codinglabs.org/articles/consistent-hashing.html

===================================

二.演算法設計

1.問題來源

一個由6臺伺服器組成的服務,每臺Server負責儲存1/6的資料,當Server1出現宕機之後,服務重新恢復可用時的場景。

如下表格可以很清楚的看到,當Server1宕機時,Hash1的服務完全不可用了,所以需要ReHash由剩餘5臺機器提供所有的資料服務,但由於每臺機器負責的資料段大小不相同,那麼需要在不同的伺服器之間大量遷移資料,並且資料遷移完成之前服務會不可用。

2.經典一致性雜湊演算法

針對ReHash的弊端,Karger提出了一種演算法,演算法的核心是”虛擬節點”。

將所有的資料對映成一組大於伺服器數量的虛擬節點,虛擬節點再對映到真實的伺服器。所以當伺服器宕機時,由於虛擬節點的數量固定不變,所有不需要ReHash,而只需要將服務不可用的虛擬節點重新遷移,這樣只需要遷移宕機節點的資料。

經典的演算法中,宕機伺服器的下一個真實節點將提供服務。

三.演算法改進

1.經典一致性雜湊演算法的問題

經典的演算法只是解決了ReHash演算法的缺陷,當本身並不完美。主要存在以下幾個問題:

(1)Server1宕機會導致Server2的服務承受一倍的資料服務,且如果Server1就此退役,那麼整個系統的負載完全不均衡了。

(2)如果所有的Server都能承受一倍的資料讀寫,那麼如果在正常情況下所有的資料寫兩份到不同的伺服器,主備或者負載均衡,宕機時直接讀備份節點的資料,根本不需要出現經典演算法中的資料遷移。

2.Dynamo改進實踐

Amazon的大資料儲存平臺”Dynamo”使用了一致性雜湊,但它並沒有使用經典演算法,而是使用了故障節點ReHash的思路。

系統將所有的虛擬節點和真實伺服器的對應關係儲存到一個配置系統,當某些虛擬節點的服務不可用時,重新配置這些虛擬節點的服務到其他真實伺服器,這樣既不用大量遷移資料,也保證了所有伺服器的負載相對均衡。

虛擬節點 0-4/5 10-14/6 15-19/7 20-24/8 24-29/9
恢復 Server0 Server2 Server3 Server4 Server5

四.演算法擴充套件

一致性雜湊演算法本身是用於解決伺服器宕機與擴容的問題,但”虛擬節點”的演算法思想有所發展,一些分散式的系統用於實現系統的負載均衡和最優訪問策略。

在真實的系統情況下,相同部署的兩套系統可能不能提供相同的服務,主要原因:

(1)硬體個體差異導致伺服器效能不同。

(2)機房交換機和網路頻寬導致IDC伺服器之間的網路通訊效率不同。

(3)使用者使用不同的網路運營商導致電信IDC和聯通IDC提供的服務效能不同。

(4)伺服器所在網路或機房遭遇攻擊。

所以完全相同的兩套系統可能也需要提供差異化的服務,通過使用虛擬節點可以靈活的動態調整,達到系統服務的最優化。

對於由2個節點,每個節點3臺伺服器組成的分散式系統,S0-1為分散式系統1的Server0,系統配置管理員可以根據系統真實的服務效率動態的調整虛擬節點與真實伺服器的對映關係,也可以由客戶系統自身根據響應率或響應時間等情況調整自身的訪問策略。

轉;http://blog.jobbole.com/80334/