14 | 緩存的使用姿勢(二):緩存如何做到高可用忿峻?

之前了解了緩存的原理逛尚、分類以及常用緩存的使用技巧。我們開始用緩存承擔(dān)大部分的讀壓力到逊,從而緩解數(shù)據(jù)庫的查詢壓力滤钱,在提升性能的同時(shí)保證系統(tǒng)的穩(wěn)定性。這時(shí)電商系統(tǒng)整體架構(gòu)演變成這個(gè)樣子:


image.png

我們在Web層和數(shù)據(jù)層之間增加了緩存層,請求會首先查詢緩存他炊,只有當(dāng)緩存中沒有需要的數(shù)據(jù)時(shí)才會查詢數(shù)據(jù)庫痊末。

在這里你需要關(guān)注緩存命中率這個(gè)指標(biāo)。一般來說捆蜀,在你的電商系統(tǒng)中幔嫂,核心緩存的命中率需要維持在99%甚至是99.9%履恩,哪怕下降1%,系統(tǒng)都會遭受毀滅性打擊飒筑。

這不是危言聳聽。假設(shè)系統(tǒng)的QPS是10000/s俏脊,每次調(diào)用會訪問10次緩存或者數(shù)據(jù)庫中的數(shù)據(jù)爷贫,那么當(dāng)緩存命中率僅僅減少1%补憾,數(shù)據(jù)庫每秒就會增加1000次請求。而一般來說我們單個(gè)MySQL節(jié)點(diǎn)的讀請求量峰值就在1500/s左右腾务,增加的這1000次請求很可能會給數(shù)據(jù)庫造成極大的沖擊削饵。

影響如此可怕窿撬,更不要說緩存節(jié)點(diǎn)故障了。而圖中單點(diǎn)部署的緩存節(jié)點(diǎn)就成了緩存系統(tǒng)中最大的隱患,那我們?nèi)绾翁嵘彺娴目捎眯阅兀?/p>

重點(diǎn):分布式緩存的高可用方案

主要選擇的方案有客戶端方案宰啦、中間代理層方案和服務(wù)端方案三大類:

  • 客戶端方案就是在客戶端配置多個(gè)緩存的節(jié)點(diǎn)饼拍,通過緩存寫入和讀取算法策略來實(shí)現(xiàn)分布式师抄,從而提高緩存的可用性。

  • 中間代理層方案就是在應(yīng)用代碼和緩存節(jié)點(diǎn)之間增加代理層辆布,客戶端所有的寫入和讀取的請求都通過代理層茶鉴,而代理層中會內(nèi)置高可用策略涵叮,幫助提升緩存系統(tǒng)的高可用伞插。

  • 服務(wù)端方案就是redis 2.4版本后提出的Redis Sentinel方案媚污。
    掌握這些方案可以幫助你抵御部分緩存節(jié)點(diǎn)故障導(dǎo)致的緩存命中率下降的影響

客戶端方案

在客戶端方案中廷雅,你需要關(guān)注緩存的寫和讀2個(gè)方面

  • 寫入數(shù)據(jù)時(shí)榜轿,需要把被寫入緩存的數(shù)據(jù)分散到多個(gè)節(jié)點(diǎn)中,即進(jìn)行數(shù)據(jù)分片甸私;
  • 讀數(shù)據(jù)時(shí)飞傀,可以利用多組的緩存來做容錯(cuò) 砸烦,提升緩存系統(tǒng)的可用性。關(guān)于讀數(shù)據(jù)唬格,這里可以時(shí)候用主從和多副本兩種策略颜说,兩種策略是為了解決不同的問題而提出的门粪。

該如何做?

1.緩存數(shù)據(jù)如何分片

單一的緩存節(jié)點(diǎn)受到機(jī)器內(nèi)存乾吻、網(wǎng)卡帶寬和單節(jié)點(diǎn)請求量的限制绎签,不能承擔(dān)比較高的并發(fā)酝锅,因此我們考慮將數(shù)據(jù)分片屈张,依照分片算法將數(shù)據(jù)打散到多個(gè)不同的節(jié)點(diǎn)上袱巨,每個(gè)節(jié)點(diǎn)上存儲部分?jǐn)?shù)據(jù)愉老。

這樣在某個(gè)節(jié)點(diǎn)故障的情況下剖效,其他節(jié)點(diǎn)也可以提供服務(wù)璧尸,保證一定的可用性。
一般來講垫竞,分片算法常見的及時(shí)Hash分片算法和一致性Hash分片算法兩種蛀序。

Has分片的算法就是對緩存的Key做哈希計(jì)算徐裸,然后對總的緩存節(jié)點(diǎn)個(gè)數(shù)取余∑锼睿可這么理解:
比如說我們部署了三個(gè)緩存節(jié)點(diǎn)組成一個(gè)緩存的集群次企,當(dāng)有新的數(shù)據(jù)要寫入時(shí)健民,我們先對這個(gè)緩存的key做比如crc32等hash算法生成hash值秉犹,然后對hash值模3稚晚,得出的結(jié)果就是要存入緩存節(jié)點(diǎn)的序號客燕。

image.png

這個(gè)算法最大的優(yōu)點(diǎn)就是簡單易理解也搓,缺點(diǎn)是當(dāng)增加或者減少緩存節(jié)點(diǎn)時(shí)涵紊,緩存總的節(jié)點(diǎn)個(gè)數(shù)變化造成計(jì)算出來的節(jié)點(diǎn)發(fā)生變化幔摸,從而造成緩存失效不可用。如果采用這種方法驱负,最好建立在你對于這組緩存命中率下降不敏感患雇,比如下面還有另外一層緩存來兜底的情況下苛吱。

當(dāng)然了又谋,用一致性Hash算法可以很好地解決增加和刪減節(jié)點(diǎn)時(shí),命中率下降的問題咧七。在這個(gè)算法中任斋,我們將整個(gè)hash值空間組織成一個(gè)虛擬的圓環(huán)废酷,然后將緩存節(jié)點(diǎn)的IP地址或者主機(jī)名做Hash取值后,放置在圓環(huán)上墨辛。當(dāng)我們需要確定某一個(gè)key需要存取到哪個(gè)節(jié)點(diǎn)上的時(shí)候睹簇,先對這個(gè)key做同樣的hash取值寥闪,確定在環(huán)上的位置疲憋,然后按照順時(shí)針方向在環(huán)上“行走”,遇到的第一個(gè)緩存節(jié)點(diǎn)就是要訪問的節(jié)點(diǎn)埃脏。比如說下面的圖剂癌,key1和key2會落入到node1中,key3,4會落到node2中旁壮,key5抡谐,node3桐猬。key6茄靠,node4。

image.png

這時(shí)如果在node1和node2之間增加一個(gè)node5料滥,你可以看到原本命中node2的key3現(xiàn)在命中node5,而其他的key都沒有變化扼雏;
同樣的道理夯膀,如果我們把node3從集群中移除诱建,那么只會影響到node5,所以在增加和刪除節(jié)點(diǎn)時(shí)茎匠,只有少數(shù)的key會“漂移”到其他節(jié)點(diǎn)上汽抚,而大部分的key命中的節(jié)點(diǎn)還是會保持不變伯病,從而可以保證命中率不會大幅下降午笛。
image.png

不過事情總有兩面性药磺。雖然這個(gè)算法對命中率的影響比較小癌佩,但還是存在問題:

  • 緩存節(jié)點(diǎn)在圓環(huán)上分布不平均,會造成部分緩存節(jié)點(diǎn)的壓力較大我碟;當(dāng)某個(gè)節(jié)點(diǎn)故障時(shí)矫俺,這個(gè)節(jié)點(diǎn)所要承擔(dān)的所有訪問會轉(zhuǎn)移到另一個(gè)節(jié)點(diǎn)上厘托,會對后面的節(jié)點(diǎn)造成壓力稿湿。
  • 一致性Hash算法的臟數(shù)據(jù)問題缎罢。

極端情況下,比如一個(gè)有三個(gè)節(jié)點(diǎn)ABC承擔(dān)整體的訪問舰始,每個(gè)節(jié)點(diǎn)的訪問量平均丸卷,A故障后询刹,B將承擔(dān)雙倍的壓力凹联,當(dāng)B承擔(dān)不了流量崩潰后蔽挠,C也將因?yàn)橐袚?dān)原先3倍的流量而崩潰,這就造成了整體緩存系統(tǒng)的雪崩比原。

很可怕但是不用擔(dān)心,程序員就是要能夠創(chuàng)造性的解決各種問題雇寇,所以你可以在一致性hash算法中引入虛擬節(jié)點(diǎn)的概念锨侯。
它講一個(gè)緩存節(jié)點(diǎn)計(jì)算多個(gè)hash值分散到圓環(huán)的不同位置识腿,這樣既實(shí)現(xiàn)了數(shù)據(jù)的平均造壮,而且當(dāng)某一個(gè)節(jié)點(diǎn)故障或者退出的時(shí)候耳璧,它原先承擔(dān)的key將以更加平均的方式分配到其他節(jié)點(diǎn)上旨枯,從而避免雪崩的發(fā)生。

其次攀隔,就是一致性hash算法的臟數(shù)據(jù)問題皂贩。為什么會產(chǎn)生臟數(shù)據(jù)?比如說昆汹,在集群中有兩個(gè)節(jié)點(diǎn)AB明刷,客戶端初始寫入一個(gè)key為k,值為3的緩存數(shù)據(jù)到A中满粗。這時(shí)如果要更新K的值為4辈末,但是緩存A恰好和客戶端連接出現(xiàn)了問題,那這次寫入請求會寫入到B中映皆,
接下來緩存A和客戶端的連接恢復(fù),當(dāng)客戶端要獲取K的值時(shí)捅彻,就會獲取到存再A中的臟數(shù)據(jù)3组去,而不是B中的4。

所以在使用一致性hash算法時(shí)一定要設(shè)置緩存的過期時(shí)間步淹。這樣當(dāng)發(fā)生漂移時(shí)从隆,之前存儲的臟數(shù)據(jù)可能已經(jīng)過期湾戳,就可以減少存在臟數(shù)據(jù)的幾率。

image.png

很顯然广料,數(shù)據(jù)分片最大的優(yōu)勢就是緩解緩存節(jié)點(diǎn)的存儲和訪問壓力,但同時(shí)它也讓緩存的使用更加負(fù)載幼驶,在批量獲取場景下艾杏,單個(gè)節(jié)點(diǎn)的訪問量并沒有減少,同時(shí)節(jié)點(diǎn)數(shù)太多會造成緩存訪問的SLA("服務(wù)等級協(xié)議"盅藻,SLA代表了網(wǎng)站服務(wù)可用性)得不到很好的保證购桑,因?yàn)楦鶕?jù)木桶原則,SLA取決于最慢氏淑、最壞的節(jié)點(diǎn)情況勃蜘,節(jié)點(diǎn)數(shù)過多也會增加出現(xiàn)問題的概率,因此推薦4到6個(gè)節(jié)點(diǎn)為佳假残。

2.Memcached的主從機(jī)制

redis本身支持主從的部署方式缭贡,但是Memcached并不支持,所以我們今天主要來了解一下Memcached的主從機(jī)制是如何在客戶端實(shí)現(xiàn)的辉懒。

在之前的項(xiàng)目中阳惹,我就遇到了單個(gè)節(jié)點(diǎn)故障導(dǎo)致數(shù)據(jù)穿透的問題,這時(shí)我為每一組master配置一組slave眶俩,更新數(shù)據(jù)時(shí)主從同步更新莹汤,讀取時(shí)優(yōu)先從slave中讀數(shù)據(jù),如果讀不到樹就穿透到Master讀取颠印,并且將數(shù)據(jù)回種到slave中以保持slave數(shù)據(jù)的熱度纲岭。

主從機(jī)制最大的優(yōu)點(diǎn)是當(dāng)木一個(gè)slave宕機(jī)時(shí),還會有master作為兜底线罕,不會有大量請求穿透到數(shù)據(jù)庫的情況發(fā)生止潮,提升了緩存系統(tǒng)的高可用性。

image.png

3.多副本

其實(shí)钞楼,主從方式已經(jīng)能夠解決大部分場景的問題沽翔,但是對于極端流量的場景下,一組slave通常來說不能完全承擔(dān)所有流量窿凤,slave網(wǎng)卡寬帶可能會成為瓶頸仅偎。

為了解決這個(gè)問題,我們考慮在master/slave之前增加一層副本層雳殊,整體架構(gòu)是這樣:


image.png

在這個(gè)方案中橘沥,當(dāng)客戶端發(fā)起查詢請求時(shí),請求首先會從多個(gè)副本組中選取一個(gè)副本組發(fā)起查詢夯秃,如果查詢失敗就繼續(xù)查詢master/salve座咆,并且將查詢的結(jié)果回種到所有副本組中痢艺,避免副本組中臟數(shù)據(jù)的存在。

基于成本考慮介陶,每一個(gè)副本組容量比Master和slave要小堤舒,因此它只存儲了更加熱的數(shù)據(jù)。在這套架構(gòu)中哺呜,master和slave的請求量會大大減少舌缤,為了保證他們存儲數(shù)據(jù)的熱度,在時(shí)間后只能怪我們會把master和slave作為一組副本組使用某残。

中間代理層方案

雖然客戶端方案已經(jīng)能解決大部分的問題国撵,但是只能在單一語言系統(tǒng)之間復(fù)用。例如微博用java實(shí)現(xiàn)了這一套邏輯玻墅,PHP就難以復(fù)用介牙。而中間代理層的方案就可以解決這個(gè)問題。你可以將客戶端解決方案的經(jīng)驗(yàn)移植到代理層中澳厢,通過通用的協(xié)議(如redis協(xié)議)來實(shí)現(xiàn)在其他語言中的復(fù)用环础。

如果你來自研緩存代理層,你就可以將客戶端方案中的高可用邏輯封裝在代理層代碼里剩拢,這樣用戶在使用你的代理層的時(shí)候就不需要關(guān)心緩存的高可用是如何做的喳整,只需要依賴代理層就好了。

除此以外裸扶,業(yè)界也有很多中間代理層方案框都,它們的原理基本上可以由一張圖來概括:


image.png

從圖中可以看出,所有緩存的讀寫請求都是經(jīng)過代理層完成呵晨。代理層是無狀態(tài)的魏保,主要負(fù)責(zé)讀寫請求的路由功能,并且在其中內(nèi)置了一些高可用的邏輯摸屠。

服務(wù)端方案

redis在2.4版本中提出了redis sentinel模式來解決主從redis部署時(shí)的高可用問題谓罗,它可以在主節(jié)點(diǎn)掛了以后自動將從節(jié)點(diǎn)提升為主節(jié)點(diǎn),保證整體集群的可用性季二,整體架構(gòu)如圖:


image.png

redis sentinel也是集群部署的檩咱,這樣可以避免sentinel節(jié)點(diǎn)掛掉后造成無法自動故障恢復(fù)的問題,每一個(gè)sentinel節(jié)點(diǎn)都是無狀態(tài)的胯舷。在sentinel會配置master的地址刻蚯,sentinel會時(shí)刻監(jiān)控master的狀態(tài),當(dāng)發(fā)現(xiàn)master在配置的時(shí)間間隔內(nèi)無響應(yīng)桑嘶,就認(rèn)為master已經(jīng)掛了炊汹,sentinel會從從節(jié)點(diǎn)中選取一個(gè)提升為主節(jié)點(diǎn),并且把所有其他的從節(jié)點(diǎn)作為新主的從節(jié)點(diǎn)逃顶。sentinel集群內(nèi)部在仲裁的時(shí)候讨便,會根據(jù)配置的值來決定當(dāng)有幾個(gè)sentinel節(jié)點(diǎn)認(rèn)為主掛掉可以做主從切換的操作充甚,也就是集群內(nèi)部需要對緩存節(jié)點(diǎn)的狀態(tài)達(dá)成一致才行。

redis sentinel不屬于代理層模式霸褒,因?yàn)閷τ诰彺娴膶懭牒妥x取請求不會經(jīng)過sentinel節(jié)點(diǎn)伴找,sentinel節(jié)點(diǎn)在架構(gòu)上和主從是平級的,是作為管理者存在的废菱,所以可以認(rèn)為是在服務(wù)端提供的一種高可用方案技矮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市昙啄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寸五,老刑警劉巖梳凛,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異梳杏,居然都是意外死亡韧拒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門十性,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叛溢,“玉大人,你說我怎么就攤上這事劲适】簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵霞势,是天一觀的道長烹植。 經(jīng)常有香客問我,道長愕贡,這世上最難降的妖魔是什么草雕? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮固以,結(jié)果婚禮上墩虹,老公的妹妹穿的比我還像新娘。我一直安慰自己憨琳,他們只是感情好诫钓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篙螟,像睡著了一般尖坤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闲擦,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天慢味,我揣著相機(jī)與錄音场梆,去河邊找鬼。 笑死纯路,一個(gè)胖子當(dāng)著我的面吹牛或油,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驰唬,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼顶岸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叫编?” 一聲冷哼從身側(cè)響起辖佣,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搓逾,沒想到半個(gè)月后卷谈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霞篡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年世蔗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朗兵。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡污淋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出余掖,到底是詐尸還是另有隱情寸爆,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布盐欺,位于F島的核電站而昨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏找田。R本人自食惡果不足惜歌憨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望墩衙。 院中可真熱鬧务嫡,春花似錦、人聲如沸漆改。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挫剑。三九已至去扣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間樊破,已是汗流浹背愉棱。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工唆铐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奔滑。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓艾岂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朋其。 傳聞我的和親對象是個(gè)殘疾皇子王浴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容