緩存穿透
指查詢一個(gè)一定不存在的數(shù)據(jù)街立,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到 DB 去查詢埠通,大并發(fā)下可能導(dǎo)致 DB 掛掉赎离。
解決方案:
- 查詢返回的數(shù)據(jù)為空,仍把這個(gè)空結(jié)果進(jìn)行緩存端辱,但過(guò)期時(shí)間會(huì)比較短梁剔;
- 布隆過(guò)濾器:將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的 bitmap 中圾浅,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè) bitmap 攔截掉,從而避免了對(duì) DB 的查詢憾朴。
緩存擊穿
對(duì)于設(shè)置了過(guò)期時(shí)間的 key,緩存在某個(gè)時(shí)間點(diǎn)過(guò)期的時(shí)候喷鸽,恰好這時(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 壓垮做祝。
解決方案:
- 使用互斥鎖:當(dāng)緩存失效時(shí)砾省,不立即去 load db,先使用如 Redis 的 setnx 去設(shè)置一個(gè)互斥鎖混槐,只有一個(gè)請(qǐng)求(可以做成異步)去DB查詢编兄,當(dāng)操作成功返回時(shí)再進(jìn)行 load db 的操作并回設(shè)緩存,其他請(qǐng)求自旋等待重查緩存声登。
- 永遠(yuǎn)不過(guò)期:物理不過(guò)期狠鸳,但邏輯過(guò)期(后臺(tái)異步線程或定時(shí)任務(wù)去刷新)。
緩存雪崩
設(shè)置緩存時(shí)采用了相同的過(guò)期時(shí)間悯嗓,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效件舵,請(qǐng)求全部轉(zhuǎn)發(fā)到 DB,DB 瞬時(shí)壓力過(guò)重雪崩脯厨。
解決方案:
- 將緩存失效時(shí)間分散開铅祸,比如可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值, 比如 1-5 分鐘隨機(jī)合武,這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低临梗,就很難引發(fā)集體失效 的事件。
- 定時(shí)刷新稼跳,適用于需要同時(shí)失效的業(yè)務(wù)場(chǎng)景盟庞,業(yè)務(wù)層再規(guī)定時(shí)間不對(duì)外提供服務(wù)(比如0點(diǎn)更新數(shù)據(jù))
三者區(qū)別:穿透是沒(méi)有key,擊穿是某一個(gè) key岂贩,雪崩是很多 key茫经。
布隆過(guò)濾器:這個(gè)布隆過(guò)濾算法,在回答“不是”上是肯定的(既100%不存在)萎津,在回答“是”上面存在概論(可能存在也可能不存在卸伞,算法設(shè)計(jì)得當(dāng),存在的概率可以遠(yuǎn)大于不存在的概率)锉屈。