緩存擊穿
假設一個緩存系統中存在一個熱Key,每分每秒都有大量的請求訪問這個key,那么當這個熱key因為過期而失效,一瞬間所有的請求直接打到DB上,這種場景稱做緩存擊穿。

為了避免這種問題業界一般有如下解決方案
1.互斥鎖
當緩存過期時,常見的邏輯是直接請求DB,然后再set回緩存中。為了避免緩存擊穿的問題,可以在請求DB的地方加一個鎖(如果是分布式系統就需要使用分布式鎖),爭取到鎖的就去訪問DB,沒爭取到的就阻塞一段時間再請求緩存,減少直接打到DB的請求。
2.永不過期
不給key設置有效期,讓key永不過期,然后以定時任務的形式,主動去更新緩存。
3.邏輯過期
同樣不給key設置有效期,而是將expired值作為緩存數據的一個字段放入緩存中,取出來時校驗一下是否過期,如果過期了則重新設置有效期,並起一個異步線程去更新這緩存。
緩存雪崩
假設一個緩存系統中,大量的key用的都是同一個expired值,那么在某一瞬間,這些key可能會集體全部失效,所有的請求直接打到DB上,這種場景稱作緩存雪崩。

如何解決?
1.隨機過期時間
將數據寫入緩存時往往會設置一個expired值,為了避免在某一時間統統全部過期,可以在expired值的基礎上加上1~5min的隨機值,避免這種情況。這樣緩存就不會在某一瞬間突然全部過期了。
緩存穿透
當用戶訪問一個不存在的key時,緩存取不到,按邏輯就是從庫里面取,這種請求一多,打到DB的請求也就增加了,這種場景稱作緩存擊穿。
如下,用戶不斷請求用戶信息,但ID都為無效的負數,緩存里面沒有,所有請求可能直接打到DB上,如果是惡意請求的話,危害頗大。
GET /user/-1 GET /user/-2 .... GET /user/-3

1.緩存不存在的值
如果查詢到一個空的結果時,可以仍然將這個空的結果進行緩存,下次在請求的話就會這就返回這個空的結果而不是請求DB。當然,如果這種請求一多,存儲里就會存儲大量這種無效值,對緩存的空間也是一種壓力,所以推薦使用下面BloomFilter的方式。
2.BloomFilter
BloomFilter的特性就是當BloomFilter認為有數據時,是可能有,當認為沒有數據時,那就是真沒有。故可以利用BloomFilter的特性,擋掉這些不存在的請求。
緩存預熱
系統剛啟動,緩存還未完全構建,但是用戶不會管這么多,直接一股腦的訪問過來,請求又直接打到DB了。如果遇到這種場景,可以利用緩存預熱的思想,在系統啟動時調用一個后台接口,構建一遍緩存。
