一致性哈希算法在分布式缓存中的应用
一、應用場景
假設我們有一個網站,最近發現隨著流量增加,服務器壓力越來越大,之前直接讀寫數據庫的方式不太給力了,于是我們想引入Redis作為緩存機制。現在我們一共有三臺機器可以作為Redis服務器,如下圖所示。
二、要解決的問題
一般來說我們在大規模訪問,大并發流量下都會使用到分布式緩存,即將廉價機器部署在同一個子網內,形成多機器集群,然后通過負載均衡以及一定的路由規則進行讀請求的分流,將請求映射到對應的緩存服務器上。如何對請求與緩存服務器之間進行精準映射,以及優雅的擴展,剔除緩存服務器是分布式緩存部署的痛點。接下來我們會對解決以上問題的一些傳統做法進行分析。
- 最簡策略-隨機選取:含義:將每一次Redis請求隨機發送到一臺Redis服務器.
- 產生的問題:同一份數據可能被存在不同的機器上而造成數據冗余。有可能某數據已經被緩存但是訪問卻沒有命中,因為無法保證對相同key的所有訪問都被發送到相同的服務器。因此,隨機策略無論是時間效率還是空間效率都非常不好。解決保證相同key每次訪問同一臺Redis服務器
- 計算哈希:含義:保證對相同key的訪問會被發送到相同的服務器。
- 方案描述:
對于每次訪問,可以按如下算法計算其哈希值:h = Hash(key) % 3。其中Hash是一個從字符串到正整數的哈希映射函數。這樣,如果我們將Redis Server分別編號為0、1、2,那么就可以根據上式和key計算出服務器編號h,然后去訪問。
- 這個方法雖然解決了上面提到的兩個問題,但是存在一些其它的問題。如果將上述方法抽象,可以認為通過:h = Hash(key) % N。這個算式計算每個key的請求應該被發送到哪臺服務器,其中N為服務器的臺數,并且服務器按照0 – (N-1)編號。
對于根據請求的key進行hash 運算定位Redis緩存服務器產生的問題: 容錯性和擴展性將會變得極差.
- 容錯性:指當系統中某一個或幾個服務器變得不可用時,整個系統是否可以正確高效運行;
- 擴展性:指當加入新的服務器后,整個系統是否可以正確高效運行。
現假設有一臺服務器宕機了,那么為了填補空缺,要將宕機的服務器從編號列表中移除,后面的服務器按順序前移一位并將其編號值減一,此時每個key就要按h = Hash(key) % (N-1)重新計算;同樣,如果新增了一臺服務器,雖然原有服務器編號不用改變,但是要按h = Hash(key) % (N+1)重新計算哈希值。因此系統中一旦有服務器變更,大量的key會被重定位到不同的服務器從而造成大量的緩存不命中。而這種情況在分布式系統中是非常糟糕的。一個設計良好的分布式哈希方案應該具有良好的單調性,即服務節點的增減不會造成大量哈希重定位。一致性hash算法就是這樣一種hash方案。
三、一致性hash算法
一致性哈希算法(Consistent Hashing)最早在論文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。簡單來說,一致性哈希算法通過一個叫作一致性哈希環的數據結構實現。這個環的起點是 0,終點是 2^32 - 1,并且起點與終點連接,故這個環的整數分布范圍是 [0, 2^32-1](即哈希值是一個32位無符號整形),如下圖所示:
整個空間按順時針方向組織。0和2^32-1在零點中方向重合。
下一步將各個服務器使用H進行一個哈希,具體可以選擇服務器的ip或主機名作為關鍵字進行哈希,這樣每臺機器就能確定其在哈希環上的位置,這里假設將上文中三臺服務器使用ip地址哈希后在環空間的位置如下:
接下來使用如下算法定位數據訪問到相應服務器:將數據key使用相同的函數H計算出哈希值h,通根據h確定此數據在環上的位置,從此位置沿環順時針“行走”,第一臺遇到的服務器就是其應該定位到的服務器。
例如我們緩存服務器中有A、B、C、D四個key對應的數據對象,經過哈希計算后,在環空間上的位置如下:
截止到現在似乎還沒有什么覺得神奇的地方,請往下看:
四、應用一致性哈希算法的容錯性與可擴展性分析
- 下面分析一致性哈希算法的容錯性和可擴展性。現假設Redis-2宕機了:
我們可以看到ACD節點并不受影響,只有B節點被重定向至Redis-0。
- 下面考慮另外一種情況,如果我們在系統中增加一臺服務器Redis-3 Server:
可以發現對于C這個key,重新定位至Redis-3服務器,其他非C的key均不受影響。
綜上所述,一致性哈希算法對于節點的增減都只需重定位環空間中的一小部分數據,具有較好的容錯性和可擴展性。
五、數據傾斜問題
解決辦法-虛擬節點
一致性哈希算法在服務節點太少時,容易因為節點分部不均勻而造成數據傾斜問題。例如我們的系統中有兩臺服務器,其環分布如下:
此時必然造成大量數據集中到Redis-1上,而只有極少量會定位到Redis-0上。
為了解決這種數據傾斜問題,一致性哈希算法引入了虛擬節點機制,即對每一個服務節點計算多個哈希,每個計算結果位置都放置一個此服務節點,稱為虛擬節點。具體做法可以在服務器ip或主機名的后面增加編號來實現。例如上面的情況,我們決定為每臺服務器計算三個虛擬節點,于是可以分別計算“Redis-1 #1”、“Redis-1 #2”、“Redis-1 #3”、“Redis-0 #1”、“Redis-0 #2”、“Redis-0 #3”的哈希值,于是形成六個虛擬節點:
同時數據定位算法不變,只是多了一步虛擬節點到實際節點的映射,例如定位到“Redis-1#1”、“Redis-1#2”、“Redis-1#3”三個虛擬節點的數據均定位到Redis-1上。這樣就解決了服務節點少時數據傾斜的問題。在實際應用中,通常將虛擬節點數設置為32甚至更大,因此即使很少的服務節點也能做到相對均勻的數據分布。
六、總結
目前一致性哈希基本成為了分布式系統組件的標準配置,例如Redis的各種客戶端都提供內置的一致性哈希支持。本文只是簡要介紹了這個算法的思想,以及在分布式應用中的應用場景。
文章轉自
參考文章
總結
以上是生活随笔為你收集整理的一致性哈希算法在分布式缓存中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020游戏直播行业数据报告
- 下一篇: redis集群搭建(基于docker)