傳統(tǒng)分布式算法
傳統(tǒng)的分布式算法通常是采用hash取模的方式來處理數(shù)據(jù)與服務器節(jié)點的映射關系店展。
舉個栗子
假設有個圖片為test.jpg榛瓮,現(xiàn)在有3個服務器,我們稱之為0服務器七冲、1服務器背镇、2服務器。首先我們對這張圖片進行hash丰刊,可以拿到一個散列值隘谣,用散列值對3進行取模,取模結果為0或者1或者2啄巧。如果結果是0則將圖片存入0服務器節(jié)點上寻歧,如果是1則存入1服務器節(jié)點掌栅,如果是2則存入2服務器節(jié)點。
按照上述的方式熄求,此時假設我們有4個redis節(jié)點渣玲,分別是redis0、redis1弟晚、redis2忘衍、redis3。有20個數(shù)據(jù)卿城,這20個數(shù)據(jù)的hash結果分別為1-20枚钓。然后對4進行取模,取模的結果就是對應數(shù)據(jù)存儲的redis節(jié)點瑟押。最終數(shù)據(jù)的分配情況如圖所示搀捷。
項目運行時我們發(fā)現(xiàn)redis節(jié)點不夠用了,所以新增了一個節(jié)點多望,或者是說發(fā)現(xiàn)redis集群負載非常低嫩舟,我們可以刪除一個節(jié)點來節(jié)省資源。現(xiàn)在的場景是增加了一個節(jié)點怀偷,我們重新將這20個數(shù)據(jù)進行取模放置到5個redis節(jié)點中家厌。
如圖,其中1椎工、2饭于、3、20這四個數(shù)據(jù)在4個redis節(jié)點和5個redis節(jié)點中存儲的服務器是一樣的维蒙。所以新增了一個redis節(jié)點之后還能獲取到這4個數(shù)據(jù)掰吕,因為存儲位置沒有發(fā)生變化。
結論
20個數(shù)據(jù)在新增了一個服務器節(jié)點后只有4個數(shù)據(jù)命中颅痊,命中率是:4/20 = 20%殖熟。
當然這里只是舉例,實際生成環(huán)境數(shù)據(jù)量可能是百萬級斑响、千萬級吗讶,在實際的生產環(huán)境中可能對cache節(jié)點會有所調整,比如刪除一個cache節(jié)點恋捆,增加一個cache節(jié)點照皆。那么使用傳統(tǒng)的hash算法取模的方式將會對后臺服務器造成巨大的沖擊。很多緩存都沒有命中沸停,如果你的業(yè)務代碼是穿透型的膜毁,那就會穿過cache直擊db,很容易把數(shù)據(jù)庫搞垮。接下來就看一下Consistent hashing
一致性算法的精髓所在瘟滨。
Consistent hashing
一致性hash算法候醒,Consistent hashing
算法早在1997年就在論文《Consistent hashing and random trees》提出。
設計目標是為了解決因特網(wǎng)中的熱點(Hot spot)問題杂瘸,現(xiàn)在一致性hash算法在分布式系統(tǒng)中也得到了廣泛應用倒淫。
環(huán)形hash空間
通常hash算法都是將value映射在一個32位的key值當中。而一致性哈希則將整個哈希值空間組織成一個虛擬的圓環(huán)败玉,取值范圍是從0-2^32-1
(即哈希值是一個32位無符號整形)敌土。
把對象映射到hash空間
這里的對象就是我們真實存儲的數(shù)據(jù),以4個為例运翼,分別為object1~object4
返干。通過hash函數(shù)計算出hash值,分別為key1~key4
血淌,這四個值肯定會落在環(huán)形hash空間上矩欠。
把cache映射到hash空間
基本思想就是將對象和cache都映射到同一個hash數(shù)值空間中,并且使用相同的hash算法悠夯。即hash(cache A)=key A;
cache就是實際的緩存服務器節(jié)點癌淮,以3個為例,對cache的hash計算一般的方法可以使用cache的機器的IP地址或者機器名作為hash輸入沦补,也可以引入更多的因子乳蓄,比如端口號等。最終cache通過同一個hash算法也落在對象所在的相同的環(huán)形hash空間上策彤。
把對象映射到cache
接下來就是要考慮如何把對象映射到cache上栓袖,具體的做法就是找到對象所在環(huán)形空間的位置匣摘,順時針出發(fā)店诗,碰到的第一個cache節(jié)點就作為該對象的存儲節(jié)點。因為對象的hash和cache的hash都是固定的音榜,因此某個對象存儲的cache必然是唯一并且確定的庞瘸。這樣就找到了數(shù)據(jù)映射到cache的一個方案(如圖虛線箭頭所示)。
移除Cache
在實際的生產環(huán)境中通常對cache節(jié)點會有所調整赠叼,我們來看下一致性哈希算法是如何處理的擦囊。
比如我們移除cache B,此時只有object4無法命中嘴办,但是還是可以通過這個算法繼續(xù)找到新的cache節(jié)點cache C瞬场,object4就會存儲到cache C上。所以對于移除cache B來說涧郊,它影響的范圍僅僅是它和逆時針到達的第一個cahce節(jié)點即cache A之間的數(shù)據(jù)(如圖所示的透明區(qū)域)贯被,對于環(huán)形的其他數(shù)據(jù)節(jié)點都不會影響,影響范圍是非常小的。
添加Cache
比如我們在cache B和cache C之間新增了一個cache D彤灶,相應的object2就得更換存儲的cache節(jié)點看幼,連接到了新的cache D上。對于添加的cache D其影響的范圍是它和逆時針到達的第一個cahce節(jié)點即cache B之間的數(shù)據(jù)(如圖所示的透明區(qū)域)幌陕。
所以對于cache變動诵姜,無論是添加cache節(jié)點還是刪除cache節(jié)點,它影響的范圍都是很小的搏熄。當然這里還有優(yōu)化的空間棚唆。
理想與現(xiàn)實
理想非常豐滿,現(xiàn)實非常骨感搬卒。左圖就是理想中的情況瑟俭,A、B契邀、C節(jié)點分布的非常均勻摆寄。而現(xiàn)實呢有可能是右圖這樣,顯然大量的數(shù)據(jù)都會落在A節(jié)點上坯门,B和C節(jié)點存儲的數(shù)據(jù)會較少微饥,如果考慮隨機性而言的話。這樣會導致A節(jié)點服務器很忙古戴,負載很高欠橘,而B、C比較清閑现恼。這是由于hash的傾斜性導致的肃续。
Hash傾斜性
假設有6個數(shù)據(jù),它們是隨機均勻分布在環(huán)形hash空間上叉袍,而cache的分布則比較緊密始锚。那么根據(jù)這個算法規(guī)則數(shù)據(jù)1、2喳逛、3瞧捌、4、6則都是存儲在A節(jié)點上润文,5存儲在B節(jié)點上姐呐,C節(jié)點沒有數(shù)據(jù)。這就是hash傾斜性典蝌。hash傾斜性導致了A曙砂、B、C這三個節(jié)點負載骏掀、性能都不均勻鸠澈。
虛擬節(jié)點
為了解決hash傾斜性帶來的問題乔夯,在這個算法中就引入了虛擬節(jié)點。來看一下虛擬節(jié)點的算法原理款侵。
假設有兩個數(shù)據(jù)object1和object2末荐,對它們進行hash,我們增加了6個虛擬節(jié)點分別為v1~v6新锈,兩個對象hash之后分別落到了v2和v5虛擬節(jié)點上甲脏,然后對虛擬節(jié)點進行rehash,此時v1妹笆、v2映射到了N1這個真實節(jié)點上块请,v3、v4映射到了N2節(jié)點上拳缠,v5墩新、v6映射到了N3節(jié)點上。通過虛擬節(jié)點把真實的服務器節(jié)點進行放大窟坐,最終object1存儲到了N1節(jié)點上海渊,object2存在了N3節(jié)點上。
其工作原理就是將一個物理節(jié)點拆分為多個虛擬節(jié)點哲鸳,并且同一個物理節(jié)點的虛擬節(jié)點盡量均勻分布在Hash環(huán)上臣疑。通過虛擬節(jié)點就解決了服務節(jié)點少時數(shù)據(jù)傾斜的問題。
解決hash傾斜性
引入了虛擬節(jié)點后徙菠,對hash傾斜性的解決方案是怎樣的呢讯沈?
比如我們增加了6個虛擬節(jié)點,這6個虛擬節(jié)點最終映射到了3臺真實的cache節(jié)點婿奔,如圖所示缺狠。我們對數(shù)據(jù)進行hash后落在了環(huán)形空間上,通過算法規(guī)則最終1萍摊、3數(shù)據(jù)落在A上挤茄,4、5落在B上记餐,2驮樊、6落在C節(jié)點上薇正。 相對均勻了一些片酝。
但是虛擬節(jié)點在rehash時也存在hash傾斜性,我們可以通過調整虛擬節(jié)點的數(shù)量挖腰,把真實節(jié)點和虛擬節(jié)點分配一個良好的比例雕沿,可以想像真實節(jié)點和真實節(jié)點間都存在大量的虛擬節(jié)點,隨著節(jié)點越來越多元践,數(shù)據(jù)越來越多温鸽,那么分布會越來越均勻。并且在添加節(jié)點和刪除節(jié)點時影響也會降到最低坐榆。
命中率計算
命中率計算公式:(1-n/(n + m)) * 100%
n:服務器臺數(shù)
m:服務器變動臺數(shù)
可以看出當變動的服務器臺數(shù)越大疾渣,命中率就會越大篡诽。所以影響就會越來越小。隨著分布式集群不斷擴大時榴捡,這個算法的優(yōu)點就會很自然的迸發(fā)出來杈女。
總結
一致性哈希算法首先將整個哈希值空間(0-2^32-1)組織成一個虛擬的圓環(huán),然后將存儲對象進行hash吊圾,得到的值映射到圓環(huán)空間上达椰。然后使用相同的hash算法對cache服務器節(jié)點進行hash,并映射到相同的圓環(huán)上项乒。然后從數(shù)據(jù)映射到的位置開始順時針查找啰劲,將數(shù)據(jù)保存到找到的第一個服務器節(jié)點上。
Consistent hashing
已經最大限度的抑制了鍵的重新分布檀何,而且還可以采用虛擬節(jié)點的思想讓每個實際節(jié)點都配置100-500個虛擬節(jié)點蝇裤,這樣就能抑制分布不均勻了。同時這個算法已經最大限度的減小了服務器增減時的緩存重新分布频鉴。