title: 兩級快取實現分析之快取設定 tags:
- J2Cache
- 快取
- 雪崩
- 快取擊穿
- 快取失效 categories: 工作日誌 date: 2017-06-25 18:18:54
上篇描述了快取過期的程式碼兩級快取實現分析之快取過期
本次討論一下兩級快取如何獲取快取設定,移除,獲取
正如文章描述快取讀取順序
讀取順序 -> L1 -> L2 -> DB
複製程式碼
先描述一下快取讀取程式碼:
/**
* 獲取快取中的資料
*
* @param region : Cache Region name
* @param key : Cache key
* @return cache object
*/
public CacheObject get(String region, Object key) {
CacheObject obj = new CacheObject();
obj.setRegion(region);
obj.setKey(key);
if (region != null && key != null) {
obj.setValue(CacheManager.get(LEVEL_1, region, key));
if (obj.getValue() == null) {
obj.setValue(CacheManager.get(LEVEL_2, region, key));
if (obj.getValue() != null) {
obj.setLevel(LEVEL_2);
CacheManager.set(LEVEL_1, region, key, obj.getValue());
}
} else
obj.setLevel(LEVEL_1);
}
return obj;
}
複製程式碼
首先在localcache中查詢,如果可以獲得快取直接返回,
如果不能則去remotecache獲取如果可以獲得快取 將localcache設定快取後直接返回,
如果不能則返回空(CacheObject中的value為null)===》可以實現更多級快取
這邊隱含一個條件(高一級快取必定擁有比第一級快取更多並且準確的資料)
此處存在一個快取擊穿的問題:
我們在專案中使用快取通常都是先檢查快取中是否存在,如果存在直接返回快取內容,如果不存在就直直接查詢然後再快取查詢結果返回。這個時候如果我們查詢的某一個資料在快取中一直不存在,就會造成每一次請求都查詢DB,這樣快取就失去了意義,在流量大時,可能DB就掛掉了。
無論多級快取都存在此問題,對於此處的解決方案建議對使用快取的返回結果包裝(Optional)可以使用google或者java8的可選物件,如果db查詢或者計算結果為空,顯示的返回Absent物件,可以避免大量無效的key導致的快取擊穿問題
下面介紹快取的設定實現
public void set(String region, Object key, Object value, Integer expireInSec) {
if (region != null && key != null) {
if (value == null)
evict(region, key);
else {
// 分幾種情況
// Object obj1 = CacheManager.get(LEVEL_1, region, key);
// Object obj2 = CacheManager.get(LEVEL_2, region, key);
// 1. L1 和 L2 都沒有
// 2. L1 有 L2 沒有(這種情況不存在,除非是寫 L2 的時候失敗
// 3. L1 沒有,L2 有
// 4. L1 和 L2 都有
_sendEvictCmd(region, key);// 清除原有的一級快取的內容
CacheManager.set(LEVEL_1, region, key, value, expireInSec);
CacheManager.set(LEVEL_2, region, key, value, expireInSec);
}
}
// log.info("write data to cache region="+region+",key="+key+",value="+value);
}
複製程式碼
正如上文所述,高階快取(L2)必然承載更多低階快取所不存在的資料
首先發起命令清除所有一級快取的對應key(保證其他一級快取的值已被清除,不會出現快取不一致)
分別在各級快取設定對應的key和value
對於db或者其他計算資源來說如果過載會發生較為嚴重的後果,比如無返回,超時甚至當機。
快取雪崩就是可能出現的原因之一。
如果出現某個快取在一段時間後過期了,同時出現高併發獲取該快取將會出現快取雪崩,
首先查詢該快取發現不存在後立刻去向db獲取資料,該處可能將一瞬間的流量完全打到db上
導致db負債過高使得應用超時乃至當機
通常解決方案只能通過getCache時如果key不存在就增加一把鎖,使得其他執行緒必須等待到鎖釋放
當然還有快取失效問題
使用者在初次使用系統時,可能要針對該使用者儲存大量快取,設想場景均為24h,那麼當24h後所有快取過期
同樣可能出現大量流量打到db出現異常。
通常解決方案是在過期時間上加上一定長度的隨機數,使得快取不至於一剎那全部過期導致db流量過大