標(biāo)題: 一致性哈希算法 [打印本頁]

作者: 51黑tt    時間: 2016-3-5 17:24
標(biāo)題: 一致性哈希算法
摘要本文將會從實際應(yīng)用場景出發(fā),介紹一致性哈希算法(Consistent Hashing)及其在分布式系統(tǒng)中的應(yīng)用。首先本文會描述一個在日常開發(fā)中經(jīng)常會遇到的問題場景,借此介紹一致性哈希算法以及這個算法如何解決此問題;接下來會對這個算法進行相對詳細的描述,并討論一些如虛擬節(jié)點等與此算法應(yīng)用相關(guān)的話題。
分布式緩存問題假設(shè)我們有一個網(wǎng)站,最近發(fā)現(xiàn)隨著流量增加,服務(wù)器壓力越來越大,之前直接讀寫數(shù)據(jù)庫的方式不太給力了,于是我們想引入Memcached作為緩存機制,F(xiàn)在我們一共有三臺機器可以作為Memcached服務(wù)器,如下圖所示。


很顯然,最簡單的策略是將每一次Memcached請求隨機發(fā)送到一臺Memcached服務(wù)器,但是這種策略可能會帶來兩個問題:一是同一份數(shù)據(jù)可能被存在不同的機器上而造成數(shù)據(jù)冗余,二是有可能某數(shù)據(jù)已經(jīng)被緩存但是訪問卻沒有命中,因為無法保證對相同key的所有訪問都被發(fā)送到相同的服務(wù)器。因此,隨機策略無論是時間效率還是空間效率都非常不好。
要解決上述問題只需做到如下一點:保證對相同key的訪問會被發(fā)送到相同的服務(wù)器。很多方法可以實現(xiàn)這一點,最常用的方法是計算哈希。例如對于每次訪問,可以按如下算法計算其哈希值:
h = Hash(key) % 3
其中Hash是一個從字符串到正整數(shù)的哈希映射函數(shù)。這樣,如果我們將Memcached Server分別編號為0、1、2,那么就可以根據(jù)上式和key計算出服務(wù)器編號h,然后去訪問。
這個方法雖然解決了上面提到的兩個問題,但是存在一些其它的問題。如果將上述方法抽象,可以認為通過:
h = Hash(key) % N
這個算式計算每個key的請求應(yīng)該被發(fā)送到哪臺服務(wù)器,其中N為服務(wù)器的臺數(shù),并且服務(wù)器按照0 – (N-1)編號。
這個算法的問題在于容錯性和擴展性不好。所謂容錯性是指當(dāng)系統(tǒng)中某一個或幾個服務(wù)器變得不可用時,整個系統(tǒng)是否可以正確高效運行;而擴展性是指當(dāng)加入新的服務(wù)器后,整個系統(tǒng)是否可以正確高效運行。
現(xiàn)假設(shè)有一臺服務(wù)器宕機了,那么為了填補空缺,要將宕機的服務(wù)器從編號列表中移除,后面的服務(wù)器按順序前移一位并將其編號值減一,此時每個key就要按h = Hash(key) % (N-1)重新計算;同樣,如果新增了一臺服務(wù)器,雖然原有服務(wù)器編號不用改變,但是要按h = Hash(key) % (N+1)重新計算哈希值。因此系統(tǒng)中一旦有服務(wù)器變更,大量的key會被重定位到不同的服務(wù)器從而造成大量的緩存不命中。而這種情況在分布式系統(tǒng)中是非常糟糕的。
一個設(shè)計良好的分布式哈希方案應(yīng)該具有良好的單調(diào)性,即服務(wù)節(jié)點的增減不會造成大量哈希重定位。一致性哈希算法就是這樣一種哈希方案。
一致性哈希算法算法簡述一致性哈希算法(Consistent Hashing)最早在論文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。簡單來說,一致性哈希將整個哈希值空間組織成一個虛擬的圓環(huán),如假設(shè)某哈希函數(shù)H的值空間為0 – 232-1(即哈希值是一個32位無符號整形),整個哈?臻g環(huán)如下:
哈?臻g環(huán)

整個空間按順時針方向組織。0和232-1在零點中方向重合。
下一步將各個服務(wù)器使用H進行一個哈希,具體可以選擇服務(wù)器的ip或主機名作為關(guān)鍵字進行哈希,這樣每臺機器就能確定其在哈希環(huán)上的位置,這里假設(shè)將上文中三臺服務(wù)器使用ip地址哈希后在環(huán)空間的位置如下:

接下來使用如下算法定位數(shù)據(jù)訪問到相應(yīng)服務(wù)器:將數(shù)據(jù)key使用相同的函數(shù)H計算出哈希值h,根據(jù)h確定此數(shù)據(jù)在環(huán)上的位置,從此位置沿環(huán)順時針“行走”,第一臺遇到的服務(wù)器就是其應(yīng)該定位到的服務(wù)器。
例如我們有A、B、C、D四個數(shù)據(jù)對象,經(jīng)過哈希計算后,在環(huán)空間上的位置如下:

根據(jù)一致性哈希算法,數(shù)據(jù)A會被定為到Server 1上,D被定為到Server 3上,而B、C分別被定為到Server 2上。
容錯性與可擴展性分析下面分析一致性哈希算法的容錯性和可擴展性,F(xiàn)假設(shè)Server 3宕機了:

可以看到此時A、C、B不會受到影響,只有D節(jié)點被重定位到Server 2。一般的,在一致性哈希算法中,如果一臺服務(wù)器不可用,則受影響的數(shù)據(jù)僅僅是此服務(wù)器到其環(huán)空間中前一臺服務(wù)器(即順著逆時針方向行走遇到的第一臺服務(wù)器)之間數(shù)據(jù),其它不會受到影響。
下面考慮另外一種情況,如果我們在系統(tǒng)中增加一臺服務(wù)器Memcached Server 4:

此時A、D、C不受影響,只有B需要重定位到新的Server 4。一般的,在一致性哈希算法中,如果增加一臺服務(wù)器,則受影響的數(shù)據(jù)僅僅是新服務(wù)器到其環(huán)空間中前一臺服務(wù)器(即順著逆時針方向行走遇到的第一臺服務(wù)器)之間數(shù)據(jù),其它不會受到影響。
綜上所述,一致性哈希算法對于節(jié)點的增減都只需重定位環(huán)空間中的一小部分數(shù)據(jù),具有較好的容錯性和可擴展性。
虛擬節(jié)點一致性哈希算法在服務(wù)節(jié)點太少時,容易因為節(jié)點分部不均勻而造成數(shù)據(jù)傾斜問題。例如我們的系統(tǒng)中有兩臺服務(wù)器,其環(huán)分布如下:

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

同時數(shù)據(jù)定位算法不變,只是多了一步虛擬節(jié)點到實際節(jié)點的映射,例如定位到“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”三個虛擬節(jié)點的數(shù)據(jù)均定位到Server 1上。這樣就解決了服務(wù)節(jié)點少時數(shù)據(jù)傾斜的問題。在實際應(yīng)用中,通常將虛擬節(jié)點數(shù)設(shè)置為32甚至更大,因此即使很少的服務(wù)節(jié)點也能做到相對均勻的數(shù)據(jù)分布。
總結(jié)目前一致性哈;境蔀榱朔植际较到y(tǒng)組件的標(biāo)準配置,例如Memcached的各種客戶端都提供內(nèi)置的一致性哈希支持。本文只是簡要介紹了這個算法,更深入的內(nèi)容可以參看論文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》,同時提供一個C語言版本的實現(xiàn)供參考。
——–
作者已經(jīng)在文章中介紹的比較清楚了,在這里補充下對“一致性哈!边@個名詞的簡單說明,在這個算法中就是指的機器標(biāo)識符和存儲對象采用相同的哈希算法,從而把他們映射到同一個集合(即0-2^32-1的哈希環(huán))。






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1