問題緩存雪崩:
緩存伺服器挂掉,或者熱點緩存失效,導緻大量的請求通路DB資料庫,導緻資料庫連接配接不夠用或資料庫處理不過來,進而導緻系統不可用。
類比緩存擊穿:
緩存雪崩産生的原因--緩存曾經存在,隻是失效或者緩存伺服器挂掉
而緩存擊穿,是指通路緩存中必然不存在的資料,故意繞過緩存,直接通路資料庫導緻的
簡單描述一下緩存擊穿的解決方案:當通路資料庫中不存在的資料時,可以給這個key設定一個固定值,并設定過期時間,這樣的話,大量的通路該key的請求,都被緩存擋住了;當key存在資料時,緩存也已經失效,在去通路,就可以通路資料庫更新這個key的值了
解決方案:
1.限流: 加鎖,控制進入資料庫請求數量
private Lock lock = new ReentrantLock();
public String queryInfo(String key){
//step1:先從緩存中擷取,擷取不到,接着向下走
try{
//step2:加鎖
lock.lock();
// step3:擷取到鎖後,再次從緩存中取資料
// 這樣做的目的是,驗證是否已經有其他請求已經查詢到資料,并放入緩存中去了
// step4:到資料庫中查詢
// step5 : 查詢的結果放入緩存
}finally{
// step6: 解鎖
lock.unlock();
}
}
這種方案的缺點:
1) 線程阻塞,導緻使用者體驗不好
2) 加鎖的粒度太大,對所有進入到這個方法的請求加鎖,即所有的查詢都被一把鎖鎖住
2.服務降級 :把鎖的粒度變小,使用 ConcurrentHashMap加鎖
private Map<String,String> lockMap = new ConcurrentHashMap<>(); public String queryInfo(String key){ //step1:先從緩存中擷取,擷取不到,接着向下走 boolean lock = false; try{ //step2:類似加鎖 lock = lockMap.putIfAbsent(key,"lock") == null; //拿到鎖的線程,負責更新緩存,其他請求讀取備份緩存或者執行降級政策 if(lock){ //step3:繼續從緩存中擷取 // 這樣做的目的是,驗證是否已經有其他請求已經查詢到資料,并放入緩存中去了 // step4:到資料庫中查詢 // step5 : 查詢的結果放入緩存 ,包括備份緩存 }else{ //服務降級政策 // 政策1:從備份緩存中擷取 // 政策2:傳回一個固定值 } }finally { // 最後解鎖: lockMap.remove(key); } } |
優點:線程不阻塞,使用者體驗好
缺點:資料不一緻,緩存維護複雜
3.寫定時任務去重新整理更新熱點緩存