Redis系列(八):緩存到底該如何做到高可用?

作者:z小趙
★?一枚用心堅(jiān)持寫原創(chuàng)的“無趣”程序猿,在自身受益的同時(shí)也讓朋友們?cè)诩夹g(shù)上有所提升。
上篇文章分析比較了生產(chǎn)環(huán)境中常見的幾種緩存,本文接著來分析分析緩存如何做到高可用,大白話解釋下就是緩存到底該怎么做才能盡可能的避免緩存不可用的情況發(fā)生。
什么情況會(huì)導(dǎo)致緩存不可用?
單點(diǎn)問題:
什么是單點(diǎn)問題呢?就是我們?cè)谑褂镁彺鏁r(shí),有時(shí)候由于 QPS、內(nèi)存容量只需要一個(gè)端口(此處的一個(gè)端口是指一主一從)就可以扛住所有讀寫請(qǐng)求時(shí),比如寫 QPS 5k,讀 QPS 30k,內(nèi)存 5G;根據(jù)這個(gè)數(shù)據(jù)規(guī)模,DBA 在部署資源時(shí)會(huì)選擇只部署一個(gè)節(jié)點(diǎn)。當(dāng)緩存資源由于某些情況導(dǎo)致服務(wù)器宕機(jī)或服務(wù)不可用時(shí),由于只部署了一個(gè)端口,從而導(dǎo)致當(dāng)前整個(gè)應(yīng)用服務(wù)不可用(這種情況之前在實(shí)際生產(chǎn)環(huán)境中真實(shí)發(fā)生過,直接炸裂),這就是所謂的單點(diǎn)問題;其實(shí)在分布式架構(gòu)中,為了做到服務(wù)的高可用,要盡量去避免單點(diǎn)問題,做到雞蛋盡量不放在一個(gè)籃子里來盡量保證服務(wù)的可用性。
緩存穿透/緩存擊穿
緩存穿透/緩存擊穿是指某些時(shí)刻由于有些熱 key 失效或者是過期,導(dǎo)致在一瞬間大量請(qǐng)求繞過緩存直接打到 DB 上,由于 DB 的讀寫 qps 并不高,從而導(dǎo)致 DB 直接瞬間被打掛,尤其是在微博這種應(yīng)用上,突發(fā)熱點(diǎn)流量加上緩存設(shè)計(jì)不合理導(dǎo)致熱 key 過期,就會(huì)發(fā)生緩存擊穿的情況。
緩存雪崩
緩存雪崩是指由于緩存過期時(shí)間設(shè)計(jì)不合理,緩存數(shù)據(jù)過期時(shí)間集中,導(dǎo)致在某一時(shí)刻緩存中數(shù)據(jù)大面積過期,從而導(dǎo)致緩存的 miss 率大大增加,由于緩存沒有攔住請(qǐng)求導(dǎo)致大量請(qǐng)求落到 DB 上,最終導(dǎo)致后端 DB 資源被徹底打掛,即使重啟 DB 也會(huì)被大量請(qǐng)求瞬間再次打掛。
如何設(shè)計(jì)高可用的緩存?
單點(diǎn)問題解決方案
首先,單端口在資源申請(qǐng)階段部署為多端口的(大于一個(gè)端口),同時(shí)每個(gè)端口至少部署為一主一從且分布在不同的節(jié)點(diǎn)上;通過此種部署方式,會(huì)有如下幾個(gè)好處:
假設(shè)某個(gè)從節(jié)點(diǎn)服務(wù)不可用時(shí),將讀請(qǐng)求轉(zhuǎn)移到主節(jié)點(diǎn)上可繼續(xù)提供服務(wù),當(dāng)從節(jié)點(diǎn)恢復(fù)后再加入到集群中繼續(xù)提供服務(wù)。 假設(shè)集群中某幾個(gè)節(jié)點(diǎn)服務(wù)不可用時(shí),此時(shí)最壞的情況也只是影響部分用戶的功能使用。
其次,在多端口部署的基礎(chǔ)上,在機(jī)房層面做到多機(jī)房災(zāi)備;此種緩存的做法是:假設(shè)一個(gè)緩存部署兩份,而這兩份緩存部署在不同的機(jī)房中,這樣的話,即使其中一個(gè)機(jī)房發(fā)生極端情況,可以將流量切換到另外一個(gè)機(jī)房中,從而做到機(jī)房層面的高可用。
最后,可以使用一致性 hash 算法,使用機(jī)器的 ip 或者域名做 hash 操作,分布在一個(gè)虛擬的環(huán)上,同樣對(duì)于 key 也做相同的 hash 操作,當(dāng) key 得到一個(gè) hash 值后,順時(shí)針移動(dòng)直到遇到第一個(gè)節(jié)點(diǎn),然后將 key 對(duì)應(yīng)的 value 存儲(chǔ)到該節(jié)點(diǎn)上;此種做法是節(jié)點(diǎn)動(dòng)態(tài)上下線的時(shí)候只需要對(duì)部分 key 做 rehash 操作,但是此種方案的缺點(diǎn)是:節(jié)點(diǎn)動(dòng)態(tài)上下線后,key 經(jīng)過 rehash 操作后導(dǎo)致各個(gè)節(jié)點(diǎn)數(shù)據(jù)分布不均,也就導(dǎo)致各個(gè)節(jié)點(diǎn)的服務(wù)承載的壓力不均不可控。
緩存穿透/緩存擊穿的解決方案
緩存擊穿是由于熱 key 失效導(dǎo)致的,所以第一種方案是:可以根據(jù)業(yè)務(wù)場(chǎng)景,選擇可以將熱 key 直接全部緩存到緩存中并且永遠(yuǎn)不過期,通過此種方式來避免熱 key 因?yàn)檫^期的問題導(dǎo)致緩存擊穿;第二種方案是:由于熱 key 一般情況下并不是很多,所以我們可以考慮使用 localCache,在系統(tǒng)啟動(dòng)時(shí),預(yù)先將熱點(diǎn)數(shù)據(jù)全部加載到內(nèi)存中,只要服務(wù)器不發(fā)生宕機(jī)就可以一直正常提供服務(wù)。
緩存雪崩的解決方案
緩存雪崩是在某一時(shí)刻,緩存中數(shù)據(jù)大量集中過期導(dǎo)致緩存不可用,對(duì)于此種情況,一般是在緩存 key 設(shè)計(jì)時(shí),對(duì) key 增加一個(gè)一定時(shí)間范圍內(nèi)的隨機(jī)時(shí)間戳,使得 key 過期分散開來,從而避免所有 key 同時(shí)過期的尷尬情況。
總結(jié)
本文主要介紹了實(shí)際生產(chǎn)環(huán)境中緩存該如何做到高可用,從而避免由于緩存不可用而導(dǎo)致整個(gè)系統(tǒng)崩潰。
關(guān)于 Redis 系列文章總計(jì) 8 篇,從 Redis 基礎(chǔ)命令使用,到 Redis 基礎(chǔ)集合及常用命令的底層實(shí)現(xiàn),然后到集群搭建實(shí)戰(zhàn),然后到 Redis 的線程模型,最后到線上緩存方案設(shè)計(jì)及緩存高可用的方案,到此關(guān)于 Redis 專題暫時(shí)告一段落,但后續(xù)還會(huì)繼續(xù)更新關(guān)于緩存相關(guān)的文章,朋友們有對(duì)緩存相關(guān)知識(shí)感興趣的話題可以和作者交流,后續(xù)會(huì)持續(xù)更新更多精彩的緩存文章。
