背景
在某些電商促消活動中需要搞活動,對某些頁面的訪問量(qps)往往會非常高。如果直接讀資料庫,肯定db會承受不住。那比較常見的方案就是讓大部分相同資訊的請求都盡可能壓在cache上來緩解db的壓力,從而盡可能去滿足高併發訪問的需求
優化:這種快取技術一般用於不會經常變動資訊,並且訪問次數較多的頁面,這樣就不用每次都動態載入。
/*手動渲染 利用thymeleaf 的 thymeleafviewresolver*/
springwebcontext ctx =
newspringwebcontext
(request,response,request.
getservletcontext()
,request.
getlocale()
, model.
asmap()
;// model 就是將引數存入 ,其中的所有引數 都是為了將頁面渲染出來 放入其中,在返回乙個靜態的html原始碼
/*利用 gettemplateengine()方法的process() 方法,需要傳入模板名稱和context 變數*/
html = thymeleafviewresolver.
gettemplateengine()
.process
("goods_list"
,ctx)
;//ctx + 模板 返回原始碼
/*得到手動渲染的模板*/if(
!stringutils.
isempty
(html)
)return html;
}當訪問list頁面的時候,從快取中取如果取到就返回這個html,(這裡方法的返回格式已經設定為text/htm,這樣就是返回html的源**),如果取不到,利用thymeleafviewresolver的gettemplateengine().process和我們獲取到的資料,渲染模板
並存入快取,然後返回給前端。
一般這個頁面快取時間,也不會很長,防止資料的時效性很低。但是可以防止短時間大併發訪問。
與頁面快取相似
相比頁面快取是更細粒度快取 + 快取 更新。在實際專案中, 不會大規模使用頁面快取,因為涉及到分頁,一般只快取前面1-2頁。
物件快取就是 當用到使用者資料的時候,可以從快取中取出。比如:更新使用者密碼
/** 將從資料庫取物件 利用優化變為從快取中取 物件資料
/** 將從資料庫取物件 利用優化變為從快取中取 物件資料
* * @param id
* @return
*/public miaoshauser getbyid
(long id)
//取不到 從資料庫裡取 再放到 快取裡
user = miaoshauserdao.
getbyid
(id);if
(user !=null)
return user;
}
在進行物件更新時進行資料庫加密更新操作後,直接刪除redis內的對應使用者的redis值,但是token 快取不能刪除,而是應該修改重新設定,不然就無法登陸了(因為我們登陸是從快取中取),所以要進行更新操作,再將更新後的物件資訊存入redis中
/**更新使用者密碼方法: 涉及到物件快取 ---若更新物件快取的相關的資料 要處理快取
* 同步資料庫和快取的資訊,不然會造成資料不一致的情況
* */
public
boolean
updatepassword
(string token,
long id,string formpassword)
// 更新資料庫 資訊
miaoshauser updateuser =
newmiaoshauser()
; updateuser.
setid
(id)
;/*設定密碼 到資料庫 ,這時候 應該是formpassword ,更新密碼一定是先在前端填入 密碼,然後前端做 一次 加密傳進來*/
updateuser.
setpassword
(md5util.
formpasstodbpass
(formpassword,user.
getsalt()
)); miaoshauserdao.
updatepassword
(updateuser)
;// 更新完資料庫資訊,防止快取中資訊不一致,處理快取 且涉及到所有該物件的快取都需要處理
// 乙個 是 根據 token 獲取物件,所以需要更新 token key 的快取物件資料, 乙個是根據id 獲取物件,同理
/** 處理快取:
* 1. 刪除相關快取資料
* 2. 更新相關快取中的資料
* */
redisservice.
delete
(miaoshauserkey.getbyname,
""+id)
;//該物件快取可以直接刪,因為沒有可以從資料取
//但是token 快取不能刪除,而是應該修改重新設定,不然就無法登陸了(因為我們登陸是從快取中取)
user.
setpassword
(updateuser.
getpassword()
);//將物件 攜帶新的密碼放入快取
redisservice.
set(miaoshauserkey.token,token,user)
;return
true
;}
1.更新快取後保證資料庫中資料和快取資料一致性。 可以選擇淘汰快取和更新快取
淘汰:價效比高,僅僅會設計一次未命中,再從資料庫取
更新:操作複雜,涉及到對應的業務邏輯。
更新快取很直接,但是涉及到本次更新的資料結果需要一堆資料運算(例如更新使用者餘額,可能需要先看看有沒有優惠券等),複雜度就增加了。而淘汰快取僅僅會增加一次cache miss,代價可以忽略,所以建議淘汰快取)
2.若一定要更新,比如登陸狀態下,更新密碼,那一定要更新快取,因為 session從快取中拿,密碼不一致,會導致登陸失效
這裡先淘汰快取,在更新資料庫資訊。(若先更新在淘汰,淘汰失敗快取中有髒資料)
保證資料一致性。
高併發下快取失效問題
快取穿透 指查詢乙個一定不存在的資料,由於快取是不命中,將去查詢資料庫,但是資料庫也無此記錄,我們沒有將這次查詢的null寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義 風險 利用不存在的資料進行攻擊,資料庫瞬時壓力增大,最終導致崩潰 解決 null結果快取,並加入短...
高併發下快取失效問題
1.快取穿透 查詢乙個一定不存在的資料,由於快取一定不命中,將查詢資料庫,並且沒有將null寫入快取,這將導致這個不存在的資料每次請求都到儲存層查詢。風險 利用不存在的資料進行攻擊,資料庫瞬時壓力增大,最終導致崩潰。解決方案 null結果快取,並加入短暫過期時間。2.快取雪崩 指設定快取時key採用...
高併發下快取穿透 快取雪崩,快取擊穿
併發進來後第乙個請求到達資料庫後,得到的資料並不存在,那麼這時返回null,這個null也會同時存在快取中,然而做快取判斷是,快取中為null就會去資料庫中查詢,那麼這時後面的併發,在來查詢這個不存在的資料是都會進入資料庫 導致資料庫壓力過大,從而導致系統崩潰 快取的key大面積的失效,如100萬的...