一、緩存穿透
緩存穿透是指查詢一個根本不存在的數(shù)據(jù)解孙,緩存層和持久層都不會命中汇跨。在日常工作中出于容錯的考慮,如果從持久層查不到數(shù)據(jù)則不寫入緩存層妆距,緩存穿透將導致不存在的數(shù)據(jù)每次請求都要到持久層去查詢,失去了緩存保護后端持久的意義函匕。
造成緩存穿透的基本原因有兩個娱据。第一,自身業(yè)務代碼或者數(shù)據(jù)出現(xiàn)問題(例如:set 和 get 的key不一致)盅惜,第二中剩,一些惡意攻擊、爬蟲等造成大量空命中(爬取線上商城商品數(shù)據(jù)抒寂,超大循環(huán)遞增商品的ID)结啼。
解決方案:
有很多種方法可以有效地解決緩存穿透問題,最常見的則是采用布隆過濾器屈芜,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中郊愧,一個一定不存在的數(shù)據(jù)會被 這個bitmap攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓力井佑。另外也有一個更為簡單粗暴的方法(我們采用的就是這種)属铁,如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障)躬翁,我們仍然把這個空結果進行緩存焦蘑,但它的過期時間會很短,最長不超過五分鐘盒发。
二例嘱、緩存雪崩
? ? ? ?由于緩存層承載著大量請求狡逢,有效地保護了存儲層,但是如果緩存層由于某些原因不可用(宕機)或者大量緩存由于超時時間相同在同一時間段失效(大批key失效/熱點數(shù)據(jù)失效)拼卵,大量請求直接到達存儲層奢浑,存儲層壓力過大導致系統(tǒng)雪崩。
解決方案:
1间学、可以把緩存層設計成高可用的殷费,即使個別節(jié)點、個別機器低葫、甚至是機房宕掉详羡,依然可以提供服務。利用sentinel或cluster實現(xiàn)嘿悬。
2实柠、采用多級緩存,本地進程作為一級緩存善涨,redis作為二級緩存窒盐,不同級別的緩存設置的超時時間不同,即使某級緩存過期了钢拧,也有其他級別緩存兜底蟹漓。
3、緩存的過期時間用隨機值源内,盡量讓不同的key的過期時間不同(例如:定時任務新建大批量key葡粒,設置的過期時間相同)。
三膜钓、緩存擊穿
當前key是一個熱點key(例如一個秒殺活動)嗽交,并發(fā)量非常大。key對應的數(shù)據(jù)存在颂斜,但在redis中過期夫壁,此時若有大量并發(fā)請求過來,這些請求發(fā)現(xiàn)緩存過期一般都會從后端DB加載數(shù)據(jù)并回設到緩存沃疮,這個時候大并發(fā)的請求可能會瞬間把后端DB壓垮盒让。
解決方案:
1、分布式鎖:只允許一個線程重建緩存司蔬,其他線程等待重建緩存的線程執(zhí)行完糯彬,重新從緩存獲取數(shù)據(jù)即可
2.?永不過期:
從緩存層面來看,確實沒有設置過期時間葱她,所以不會出現(xiàn)熱點key過期后產(chǎn)生的問題撩扒,也就是“物理”不過期。
從功能層面來看,為每個value設置一個邏輯過期時間搓谆,當發(fā)現(xiàn)超過邏輯過期時間后炒辉,會使用單獨的線程去更新緩。
2種方案對比:
分布式互斥鎖:這種方案思路比較簡單泉手,但是存在一定的隱患黔寇,如果在查詢數(shù)據(jù)庫 + 和 重建緩存(key失效后進行了大量的計算)時間過長,也可能會存在死鎖和線程池阻塞的風險斩萌,高并發(fā)情景下吞吐量會大大降低缝裤!但是這種方法能夠較好地降低后端存儲負載,并在一致性上做得比較好颊郎。
“永遠不過期”:這種方案由于沒有設置真正的過期時間憋飞,實際上已經(jīng)不存在熱點key產(chǎn)生的一系列危害,但是會存在數(shù)據(jù)不一致的情況姆吭,同時代碼復雜度會增大榛做。