Redis-快取設計與效能優化
多級快取
快取穿透、快取擊穿、快取雪崩
快取穿透
快取穿透是指查詢一個根本不存在的資料,快取層和粗儲存層都不會命中,通常處於容錯的考慮,如果從儲存層查不到資料則不寫入快取層。
快取穿透將導致不存在的資料每次請求都要到儲存查詢,失去了快取保護後端儲存的意義。
造成快取穿透的基本原因有兩個:
- 自身業務程式碼或者資料出現問題。
- 一些惡意攻擊,爬蟲等造成大量空命中。
快取穿透問題解決方案:
-
快取空物件
String get(String key) {
//從快取中獲取資料
String cacheValue = cache.get(key);
//快取為空
if (StringUtils.isBlank(cacheValue)) {
//從儲存中獲取
String storageValue = storage.get(key);
cache.set(key, storageValue);
//如果儲存資料為空,需要設定一個過期時間(300秒)
if (storageValue == null) {
cache.expire(key, 60 * 5);
}
return storageValue;
} else { -
布隆過濾器
對於惡意攻擊,向伺服器請求大量不存在的資料造成的快取穿透,還可以用布隆過濾器先做一次過濾,對於不存在的資料布隆過濾器一般都能夠過濾掉,不讓請求再往後端傳送。當布隆過濾器說某個值存在時,這個值可能不存在;當它說不存在時,那就肯定不存在。
快取擊穿(失效)
由於大批量快取在同一時間失效可能導致大量請求同時穿透快取直達資料庫,可能會造成資料庫瞬間壓力過大甚至掛掉,對於這種情況,我們在批量增加快取時最好將這一批資料的快取過期時間設定為一個時間段內的不同時間。
快取雪崩
快取雪崩是指快取層支撐不住或者宕機後,流量會像奔逃的野牛一樣,打向後端儲存層。
由於快取層承載著大量請求,有效的保護了儲存層,但是如果快取層由於某些原因不能提供服務,於是大量的請求都會打到儲存層,儲存層的呼叫量會暴增,造成儲存層也會級聯宕機的情況。
預防和解決快取雪崩的問題,可以從一下三個方面進行著手:
- 保證快取層服務高可用性,比如使用Redis Sentinel或Redis Cluster。
- 依賴隔離元件為後端限流熔斷並降級。比如使用Sentinel或Hystrix限流降級元件。
- 提前演練。
熱點快取key重建優化
開發人員使用“快取+過期時間”的策略既可以加速資料讀寫,有保證資料的定期更新,這種模式基本能夠滿足絕大部分需求。但是有兩個問題如果同時出現,可能就會對應用造成致命的危害:
- 當前key是一個熱點key,併發量非常大。
- 重建快取不能在短時間按完成,可能是一個複雜計算,例如發雜的SQL、多次IO、多個依賴等。
在快取失效的瞬間,有大量執行緒來重建快取,造成後端負載加大,甚至可能會讓應用崩潰。
要解決這個問題主要就是避免大量執行緒同時重建快取。
我們可以利用互斥鎖來解決,此方法只允許一個執行緒重建快取,其他執行緒等待重建快取的執行緒執行完,重新從快取獲取資料即可。