一、redis 更新策略
- 1.定時(shí)更新緩存
可能會(huì)引起雪崩,后文細(xì)說(shuō) - 2.查詢不到更新
可以為每個(gè)緩存數(shù)據(jù),配置一個(gè)相應(yīng)的version緩存。 配置時(shí)先適配version,后取相應(yīng)緩存,以減少序列化時(shí)間調(diào)高效率。
二、redis穿透
故障描述: 緩存與數(shù)據(jù)庫(kù)都沒(méi)有的數(shù)據(jù),發(fā)起大量訪問(wèn)請(qǐng)求,對(duì)后端造成很大的壓力。要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。
解決方案:
1.緩存層緩存空值。
–緩存太多空值,占用更多空間。(優(yōu)化:給個(gè)空值過(guò)期時(shí)間)
–存儲(chǔ)層更新代碼了,緩存層還是空值。(優(yōu)化:后臺(tái)設(shè)置時(shí)主動(dòng)刪除空值,并緩存把值進(jìn)去)
2.將數(shù)據(jù)庫(kù)中所有的查詢條件,放到布隆過(guò)濾器中。當(dāng)一個(gè)查詢請(qǐng)求來(lái)臨的時(shí)候,先經(jīng)過(guò)布隆過(guò)濾器進(jìn)行檢查,如果請(qǐng)求存在這個(gè)條件中,那么繼續(xù)執(zhí)行,如果不在,直接丟棄。
3.接口參數(shù)驗(yàn)簽,過(guò)濾掉特殊值,比如id= -1
4.布隆過(guò)濾器
redis中的布隆過(guò)濾器bloomfilter
redis 在 4.0 的版本中加入了 module 功能,布隆過(guò)濾器可以通過(guò) module 的形式添加到 redis 中。
bloomfilter就類似于一個(gè)hash set,用于快速判某個(gè)元素是否存在于集合中,
其典型的應(yīng)用場(chǎng)景就是
將所有可能存在的數(shù)據(jù)緩存,放到布隆過(guò)濾器中,當(dāng)黑客訪問(wèn)不存在的緩存時(shí)迅速返回避免緩存及DB掛掉。
布隆過(guò)濾器存在一個(gè)定的誤判率,大約是八百萬(wàn)數(shù)據(jù)量,百分之二的誤判率。
三、redis擊穿
故障描述: 熱點(diǎn)單個(gè)key,過(guò)期,此時(shí)迎來(lái)高并發(fā)
對(duì)于一些設(shè)置了過(guò)期時(shí)間的key,如果這些key可能會(huì)在某些時(shí)間點(diǎn)被超高并發(fā)地訪問(wèn),是一種非?!盁狳c(diǎn)”的數(shù)據(jù)。這個(gè)時(shí)候,需要考慮一個(gè)問(wèn)題:緩存被“擊穿”的問(wèn)題,這個(gè)和緩存雪崩的區(qū)別在于這里針對(duì)某一key緩存,前者則是很多key。
場(chǎng)景一:微博上,某某明星傳緋聞,兩個(gè)明星主頁(yè)被刷爆
緩存在某個(gè)時(shí)間點(diǎn)過(guò)期的時(shí)候,恰好在這個(gè)時(shí)間點(diǎn)對(duì)這個(gè)Key有大量的并發(fā)請(qǐng)求過(guò)來(lái),這些請(qǐng)求發(fā)現(xiàn)緩存過(guò)期一般都會(huì)從后端DB加載數(shù)據(jù)并回設(shè)到緩存,這個(gè)時(shí)候大并發(fā)的請(qǐng)求可能會(huì)瞬間把后端DB壓垮。
解決方案:
1.使用互斥鎖(mutex key)
業(yè)界比較常用的做法,是使用mutex。簡(jiǎn)單地來(lái)說(shuō),就是在緩存失效的時(shí)候(判斷拿出來(lái)的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者M(jìn)emcache的ADD)去set一個(gè)mutex key,當(dāng)操作返回成功時(shí),再進(jìn)行l(wèi)oad db的操作并回設(shè)緩存;否則,就重試整個(gè)get緩存的方法。
"提前"使用互斥鎖(mutex key):
在value內(nèi)部設(shè)置1個(gè)超時(shí)值(timeout1), timeout1比實(shí)際的memcache timeout(timeout2)小。當(dāng)從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過(guò)期時(shí)候,馬上延長(zhǎng)timeout1并重新設(shè)置到cache。然后再?gòu)臄?shù)據(jù)庫(kù)加載數(shù)據(jù)并設(shè)置到cache中。"永遠(yuǎn)不過(guò)期":
這里的“永遠(yuǎn)不過(guò)期”包含兩層意思:
(1) 從redis上看,確實(shí)沒(méi)有設(shè)置過(guò)期時(shí)間,這就保證了,不會(huì)出現(xiàn)熱點(diǎn)key過(guò)期問(wèn)題,也就是“物理”不過(guò)期。
(2) 從功能上看,如果不過(guò)期,那不就成靜態(tài)的了嗎?所以我們把過(guò)期時(shí)間存在key對(duì)應(yīng)的value里,如果發(fā)現(xiàn)要過(guò)期了,通過(guò)一個(gè)后臺(tái)的異步線程進(jìn)行緩存的構(gòu)建,也就是“邏輯”過(guò)期
4.資源保護(hù):
采用netflix的hystrix,可以做資源的隔離保護(hù)主線程池,如果把這個(gè)應(yīng)用到緩存的構(gòu)建也未嘗不可
5.為即將過(guò)期的key,續(xù)命:
緩存中取值,發(fā)現(xiàn)即將過(guò)期,追加一個(gè)小的時(shí)間值,延長(zhǎng)有效期。
6.限流: 比如說(shuō)使用消息隊(duì)列,讓流量在消息隊(duì)列中囤積下,逐個(gè)消費(fèi),緩解后端壓力。
四、redis雪崩
故障描述:
緩存雪崩是指在我們?cè)O(shè)置緩存時(shí)采用了相同的過(guò)期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請(qǐng)求全部轉(zhuǎn)發(fā)到DB,DB瞬時(shí)壓力過(guò)重雪崩
場(chǎng)景一:同一時(shí)間點(diǎn),緩存全部失效:
比如:有的電商網(wǎng)站在項(xiàng)目重啟時(shí),將全部商品信息加入緩存中,并設(shè)置等長(zhǎng)的有效期。到某一時(shí)間點(diǎn),緩存有效期過(guò)期,大量緩存失效,如果遇上高并發(fā),請(qǐng)求全部打在后端數(shù)據(jù)庫(kù)上。
場(chǎng)景二:穿透誘發(fā)雪崩
短時(shí)間內(nèi)大量的請(qǐng)求無(wú)法命中緩存,請(qǐng)求穿透到數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)繁忙,請(qǐng)求超時(shí)。
大量的請(qǐng)求超時(shí)還會(huì)引發(fā)更多的重試請(qǐng)求,更多的重試請(qǐng)求讓數(shù)據(jù)庫(kù)更加繁忙,這樣惡性循環(huán)導(dǎo)致系統(tǒng)雪崩。
解決方案:
1.設(shè)置緩存超時(shí)時(shí)間的時(shí)候加上一個(gè)隨機(jī)的時(shí)間長(zhǎng)度,比如這個(gè)緩存key的超時(shí)時(shí)間是固定的5分鐘加上隨機(jī)的2分鐘,醬紫可從一定程度上避免雪崩問(wèn)題;
2.熱點(diǎn)數(shù)據(jù)永不過(guò)期,數(shù)據(jù)庫(kù)更新時(shí)同步更新緩存 (如:電商首頁(yè)信息)
3.互斥鎖排隊(duì)
根據(jù)key獲取value值為空時(shí),鎖上,從數(shù)據(jù)庫(kù)中l(wèi)oad數(shù)據(jù)后再釋放鎖。若其它線程獲取鎖失敗,則等待一段時(shí)間后重試。這里要注意,分布式環(huán)境中要使用分布式鎖(Redisson),單機(jī)的話用普通的鎖(synchronized、Lock)
- 灰度發(fā)布 + cahe Aside緩存更新策略:
cahe Aside就是由升哥提供的我們沿用至今的緩存更新策略:
應(yīng)用程序先從緩存中取數(shù)據(jù),不存在,則從數(shù)據(jù)庫(kù)中取數(shù)據(jù),成功后,放到緩存中。
更新是先更新數(shù)據(jù)庫(kù),成功后,讓緩存失效
可以配合采用灰度發(fā)布的方式,先接入少量請(qǐng)求,再逐步增加系統(tǒng)的請(qǐng)求數(shù)量,直到全部請(qǐng)求都切換完成。