5分鐘理解一致性哈希算法

前言

一致性哈希算法(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從新計算。markdown

一樣,若是新增一臺服務器,規則也一樣須要從新計算,h = Hash(key) % 4。所以,系統中若是有服務器更變,會直接影響到Hash值,大量的key會重定向到其餘服務器中,形成緩存命中率下降,而這種狀況在分佈式系統中是十分糟糕的。架構

一個設計良好的分佈式哈希方案應該具備良好的單調性,即服務節點的變動不會形成大量的哈希重定位。一致性哈希算法由此而生~分佈式

2 一致性哈希算法

一致哈希 是一種特殊的哈希算法。在使用一致哈希算法後,哈希表槽位數(大小)的改變平均只須要對 K/n 個關鍵字從新映射,其中K是關鍵字的數量, n是槽位數量。然而在傳統的哈希表中,添加或刪除一個槽位的幾乎須要對全部關鍵字進行從新映射。函數

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

哈希環
整個空間按順時針方向組織,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#一、 RedisService1#二、 RedisService1#三、 RedisService2#一、 RedisService2#二、 RedisService2#3,具體位置以下圖所示:

虛擬節點

對於數據定位的hash算法仍然不變,只是增長了虛擬節點到實際節點的映射。例如,數據C保存到虛擬節點Redis1#2,實際上數據保存到Redis1中。這樣,就能解決服務節點少時數據不平均的問題。在實際應用中,一般將虛擬節點數設置爲32甚至更大,所以即便不多的服務節點也能作到相對均勻的數據分佈

總結

本文簡要的介紹了一致性哈希算法,目前一致性哈希算法基本成爲了分佈式系統組件的標準配置,所以,咱們十分有必要了解該算法。


房清

廣州蘆葦科技Java開發團隊

蘆葦科技-廣州專業互聯網軟件服務公司

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

關注咱們的公衆號,瞭解更多

想和咱們一塊兒奮鬥嗎?lagou搜索「 蘆葦科技 」或者投放簡歷到 server@talkmoney.cn 加入咱們吧

關注咱們,你的評論和點贊對咱們最大的支持

相關文章
相關標籤/搜索