1. 概述
緩存穿透和緩存雪崩是在實際項目中,經(jīng)常能遇到的問題。
今天我們就簡單聊聊緩存穿透和緩存雪崩的這兩個話題。
2. 緩存穿透
2.1 什么是緩存穿透?
簡單說就是用戶發(fā)起請求時,始終匹配不到緩存中的數(shù)據(jù),每次都直接通過關系型數(shù)據(jù)庫進行查詢,并得到數(shù)據(jù)。
如果這個請求的并發(fā)量非常的大,非常多的用戶在同一時刻去執(zhí)行這個請求,那么會超出關系型數(shù)據(jù)庫的負載,從而導致數(shù)據(jù)庫的宕機。
2.2 解決方案一:優(yōu)化代碼邏輯
其中一個解決方案,就是編寫代碼時,邏輯要嚴謹,反復自測,保證任何條件的查詢,都一定是先經(jīng)過緩存進行查詢。
如果緩存中沒有查到數(shù)據(jù),則進行一次關系型數(shù)據(jù)庫的查詢,然后將查詢結果存儲到緩存中(即使查詢結果是空值,也將空值存儲到緩存中),保證下一次查詢可以從緩存中獲取。
當然,由于數(shù)據(jù)庫中的數(shù)據(jù)會隨時變化,緩存是需要有過期時間的。
2.3 解決方案二:布隆過濾器
2.3.1 布隆過濾器簡介
布隆過濾器能夠很快的判斷某個元素是否已存在集合中。
布隆過濾器占用內存小,讀寫非???。
布隆過濾器適合于緩存中存在過某key才去查詢緩存,沒存在過,就不去查詢直接返回空的場景。
布隆過濾器通常放在緩存前面執(zhí)行,可以將緩存的key放進布隆過濾器中,讀取數(shù)據(jù)時,如果布隆過濾器判斷緩存的key存在,才會到緩存中去查詢,不存在就直接返回空,大大降低了緩存穿透的可能。
布隆過濾器要注意的兩個問題:
1)有一定的誤判率:由于布隆過濾器本身的機制,是會有一定的誤判率,也就是說這個key值其實在緩存中不存在,但布隆過濾器會返回其存在。
2)無法刪除:緩存的數(shù)據(jù)是會被刪除的,但布隆過濾器由于本身機制的限制,是不能執(zhí)行刪除操作的。
由于以上兩個問題,會導致程序會在key值不存在的情況下去訪問緩存,也就是說會有多訪問緩存的情況,這個其實是沒有什么影響的,在緩存上再加一層判斷就可以了。
2.3.2 布隆過濾器的使用
1)添加依賴
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
2)代碼示例
// 第一個參數(shù)是字符集
// 第二個參數(shù)是容器的長度,值越大,誤判率越低
// 第三個參數(shù)是誤判率,用于指定誤判率,值越小誤判率越低
BloomFilter<String> bloomFilter = BloomFilter.create(
Funnels.stringFunnel(StandardCharsets.UTF_8),
100000, 0.001);
// 放入元素,可以是緩存的key
bloomFilter.put("user:1");
bloomFilter.put("user:2");
// 判斷元素是否存在
boolean isExist = bloomFilter.mightContain("user:3");
3.緩存雪崩
3.1 什么是緩存雪崩?
由于數(shù)據(jù)庫中的數(shù)據(jù)是隨時變化的,因此緩存中的key通常都是有過期時間的。
在某一時刻,緩存中的大面積的key都失效了,恰好此時,很多請求并發(fā)到來,直接訪問了關系型數(shù)據(jù)庫,從而導致數(shù)據(jù)庫宕機,這就是緩存雪崩。
3.2 如何預防緩存雪崩
1)緩存永不過期
緩存不設置過期時間,而是使用程序手動讓其過期。
2)錯開緩存的過期時間
在設置緩存過期時間時,加一個固定范圍的隨機數(shù),從而錯開緩存過期時間。
4.綜述
今天簡單聊了一下緩存穿透和緩存雪崩,希望能對大家的工作有所幫助。
歡迎大家多多評論交流,共同成長。
關注追風人聊Java,每天更新Java干貨。