5分鐘理解一致性雜湊演算法

廣州蘆葦科技Java開發團隊發表於2019-01-02

前言

一致性雜湊演算法(Consistent Hashing)在分散式系統的應用還是十分廣泛的,本文儘量結合業務場景快速講解一致性雜湊演算法的應用及與其相關的話題。

1 分散式快取

隨著業務的擴充套件,流量的劇增,單體專案逐漸劃分為分散式系統。對於經常使用的資料,我們可以使用Redis作為快取機制,減少資料層的壓力。因此,重構後的系統架構如下圖所示:

簡單架構

優化最簡單的策略就是,把常用的資料儲存到Redis中,為了實現高可用使用了3臺Redis(沒有設定叢集,叢集至少要6臺)。每次Redis請求會隨機傳送到其中一臺,但是這種策略會引發如下兩個問題:

  • 同一份資料可能在多個Redis資料庫,造成資料冗餘
  • 某一份資料在其中一臺Redis資料庫已存在,但是再次訪問Redis資料庫,並沒有命中資料已存在的庫。無法保證對相同的key的所有訪問都傳送到相同的Redis中

要解決上述的問題,我們需要稍稍改變一些key存入Redis的規則:使用hash演算法 例如,有三臺Redis,對於每次的訪問都可以通過計算hash來求得hash值。 如公式 h=hash(key)%3,我們把Redis編號設定成0,1,2來儲存對應hash計算出來的值,h的值等於Redis對應的編號。 但是hash演算法也會面臨容錯性和擴充套件性的問題。容錯性是指當系統中的某個服務出現問題時,不能影響其他系統。擴充套件性是指當加入新的伺服器後,整個系統能正確高效執行。

現假設有一臺Redis伺服器當機了,那麼為了填補空缺,要將當機的伺服器從編號列表中移除,後面的伺服器按順序前移一位並將其編號值減一,此時每個key就要按h = Hash(key) % 2重新計算。

同樣,如果新增一臺伺服器,規則也同樣需要重新計算,h = Hash(key) % 4。因此,系統中如果有伺服器更變,會直接影響到Hash值,大量的key會重定向到其他伺服器中,造成快取命中率降低,而這種情況在分散式系統中是十分糟糕的。

一個設計良好的分散式雜湊方案應該具有良好的單調性,即服務節點的變更不會造成大量的雜湊重定位。一致性雜湊演算法由此而生~

2 一致性雜湊演算法

一致雜湊 是一種特殊的雜湊演算法。在使用一致雜湊演算法後,雜湊表槽位數(大小)的改變平均只需要對 K/n 個關鍵字重新對映,其中K是關鍵字的數量, n是槽位數量。然而在傳統的雜湊表中,新增或刪除一個槽位的幾乎需要對所有關鍵字進行重新對映。

簡單的說,一致性雜湊是將整個雜湊值空間組織成一個虛擬的圓環,如假設雜湊函式H的值空間為0-2^32-1(雜湊值是32位無符號整形),整個雜湊空間環如下:

雜湊環
整個空間按順時針方向組織,0和2^32-1在零點中方向重合。

接下來,把伺服器按照IP或主機名作為關鍵字進行雜湊,這樣就能確定其在雜湊環的位置。

雜湊環2
然後,我們就可以使用雜湊函式H計算值為key的資料在雜湊環的具體位置h,根據h確定在環中的具體位置,從此位置沿順時針滾動,遇到的第一臺伺服器就是其應該定位到的伺服器。

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

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

3 容錯性和擴充套件性

那麼使用一致性雜湊演算法的容錯性和擴充套件性如何呢?

3.1 容錯性

假如RedisService2當機了,那麼會怎樣呢?

Redis2當機

那麼,資料B對應的節點儲存到RedisService3中。因此,其中一臺當機後,干擾的只有前面的資料(原資料被儲存到順時針的下一個伺服器),而不會干擾到其他的資料。

3.2 擴充套件性

下面考慮另一種情況,假如增加一臺伺服器Redis4,具體位置如下圖所示:

RedisServicee4
原本資料C是儲存到Redis3中,但由於增加了Redis4,資料C被儲存到Redis4中。干擾的也只有Redis3而已,其他資料不會受到影響。

因此,一致性雜湊演算法對於節點的增減都只需重定位換空間的一小部分即可,具有較好的容錯性和可擴充套件性

4 虛擬節點

前面部分都是講述到Redis節點較多和節點分佈較為均衡的情況,如果節點較少就會出現節點分佈不均衡造成資料傾斜問題。

例如,我們的的系統有兩臺Redis,分佈的環位置如下圖所示:

雜湊環
這會產生一種情況,Redis1的hash範圍比Redis2的hash範圍大,導致資料大部分都儲存在Redis1中,資料儲存不平衡。

為了解決這種資料儲存不平衡的問題,一致性雜湊演算法引入了虛擬節點機制,即對每個節點計算多個雜湊值,每個計算結果位置都放置在對應節點中,這些節點稱為虛擬節點

具體做法可以在伺服器IP或主機名的後面增加編號來實現,例如上面的情況,可以為每個服務節點增加三個虛擬節點,於是可以分為 RedisService1#1、 RedisService1#2、 RedisService1#3、 RedisService2#1、 RedisService2#2、 RedisService2#3,具體位置如下圖所示:

虛擬節點

對於資料定位的hash演算法仍然不變,只是增加了虛擬節點到實際節點的對映。例如,資料C儲存到虛擬節點Redis1#2,實際上資料儲存到Redis1中。這樣,就能解決服務節點少時資料不平均的問題。在實際應用中,通常將虛擬節點數設定為32甚至更大,因此即使很少的服務節點也能做到相對均勻的資料分佈

總結

本文簡要的介紹了一致性雜湊演算法,目前一致性雜湊演算法基本成為了分散式系統元件的標準配置,因此,我們十分有必要了解該演算法。


房清

廣州蘆葦科技Java開發團隊

蘆葦科技-廣州專業網際網路軟體服務公司

抓住每一處細節 ,創造每一個美好

關注我們的公眾號,瞭解更多

想和我們一起奮鬥嗎?lagou搜尋“ 蘆葦科技 ”或者投放簡歷到 server@talkmoney.cn 加入我們吧

5分鐘理解一致性雜湊演算法

關注我們,你的評論和點贊對我們最大的支援

相關文章