擊穿:指的是單個key在緩存中查不到,去數(shù)據(jù)庫查詢,這樣如果數(shù)據(jù)量不大或者并發(fā)不大的話是沒有什么問題的。
如果數(shù)據(jù)庫數(shù)據(jù)量大并且是高并發(fā)的情況下那么就可能會造成數(shù)據(jù)庫壓力過大而崩潰
注意:這里指的是單個key發(fā)生高并發(fā)!!! ? ? ? ?(推薦學(xué)習(xí):Redis視頻教程)
解決方案:
1) 通過synchronized+雙重檢查機制:某個key只讓一個線程查詢,阻塞其它線程
在同步塊中,繼續(xù)判斷檢查,保證不存在,才去查DB。
例如:
?private?static?volaite?Object?lockHelp=new?Object(); ???public?String?getValue(String?key){ ?????String?value=redis.get(key,String.class); ?????if(value=="null"||value==null||StringUtils.isBlank(value){ ?????????synchronized(lockHelp){ ????????????????value=redis.get(key,String.class); ?????????????????if(value=="null"||value==null||StringUtils.isBlank(value){ ??????????????????????value=db.query(key); ??????????????????????redis.set(key,value,1000); ??????????????????} ????????????} ???????????}???? ????????return?value; ???}
缺點: 會阻塞其它線程
2) 設(shè)置value永不過期
這種方式可以說是最可靠的,最安全的但是占空間,內(nèi)存消耗大,并且不能保持?jǐn)?shù)據(jù)最新 這個需要根據(jù)具體的業(yè)務(wù)邏輯來做?
個人覺得如果要保持?jǐn)?shù)據(jù)最新不放這么試試,僅供參考:
起個定時任務(wù)或者利用TimerTask 做定時,每個一段時間多這些值進(jìn)行數(shù)據(jù)庫查詢更新一次緩存,當(dāng)然前提時不會給數(shù)據(jù)庫造成壓力過大(這個很重要)
3) 使用互斥鎖(mutex key)
業(yè)界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者M(jìn)emcache的ADD)去set一個mutex key,當(dāng)操作返回成功時,再進(jìn)行l(wèi)oad db的操作并回設(shè)緩存;否則,就重試整個get緩存的方法。
SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設(shè)置,可以利用它來實現(xiàn)鎖的效果。在redis2.6.1之前版本未實現(xiàn)setnx的過期時間,所以這里給出兩種版本代碼參考:
public?String?get(key)?{ ??????String?value?=?redis.get(key); ??????if?(value?==?null)?{?//代表緩存值過期 ??????????//設(shè)置3min的超時,防止del操作失敗的時候,下次緩存過期一直不能load?db ??????????if?(redis.setnx(key_mutex,?1,?3?*?60)?==?1)?{??//代表設(shè)置成功 ???????????????value?=?db.get(key); ??????????????????????redis.set(key,?value,?expire_secs); ??????????????????????redis.del(key_mutex); ?????????????????????return?value; ??????????????}?else?{??//這個時候代表同時候的其他線程已經(jīng)load?db并回設(shè)到緩存了,這時候重試獲取緩存值即可 ??????????????????????sleep(10); ??????????????????????get(key);??//重試 ??????????????} ??????????}?else?{ ??????????????return?value;?????? ??????????} }
更多Redis相關(guān)技術(shù)文章,請訪問Redis視頻教程欄目進(jìn)行學(xué)習(xí)!