緩存穿透是指查詢一個一定不存在的數據,由于緩存是不命中時需要從數據庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。以下是幾種解決緩存穿透的方法:
布隆過濾器是一種空間效率極高的概率型數據結構,用于判斷一個元素是否在一個集合中。它可以告訴你一個元素“可能在集合中”或“肯定不在集合中”。
當查詢數據庫發現數據不存在時,也將這個空結果緩存起來,并設置一個較短的過期時間。
// 示例代碼
String key = "nonexistent_key";
if (cache.get(key) == null) {
Object value = database.query(key);
if (value == null) {
cache.put(key, "NULL", shortExpirationTime);
} else {
cache.put(key, value, longExpirationTime);
}
}
在緩存失效的時候,不是立即去加載數據庫,而是先使用互斥鎖,保證只有一個線程去加載數據,其他線程等待結果。
// 示例代碼
String key = "key_to_query";
if (cache.get(key) == null) {
synchronized (this) {
if (cache.get(key) == null) {
Object value = database.query(key);
cache.put(key, value, expirationTime);
}
}
}
使用布隆過濾器來過濾掉大部分不存在的鍵,對于布隆過濾器判斷為可能存在的鍵,再通過緩存空對象的方式處理。
在應用層增加一級本地緩存,比如使用Guava Cache或者Caffeine,這樣即使分布式緩存穿透,本地緩存也能提供一定的保護。
在系統啟動時,預先將熱點數據加載到緩存中,減少冷啟動時的緩存穿透問題。
在高并發場景下,可以臨時關閉某些非核心功能的緩存,保證核心功能的穩定運行。
選擇哪種方法取決于具體的業務場景和需求。通常情況下,結合多種方法使用效果會更好。