快取穿透是在客戶端/瀏覽器端請求一個不存在的key,這個key在redis中不存在,在資料庫中也不存在資料來源,每次對此key的請求從快取取得不到,就會請求資料來源。
如使用一個不存在的使用者id去存取使用者訊息,redis和資料庫中都沒有,多次進行請求可能會壓垮資料來源
一個一定不存在快取及查詢不到的數據,由於快取是不命中時被動寫入的,快取不存在,出於容錯考慮,查詢不到的數據是不會快取在redis當中,這將導致每次請求不存在的資料都會請求資料庫,失去了快取的意義。
(1)如果一個查詢傳回的資料為空(不管是資料是否不存在),我們仍然把這個空結果(null)進行緩存,設定空結果的過期時間會很短,最長不超過五分鐘
(2)設定可訪問的名單(白名單):使用bitmaps類型定義一個可以訪問的名單,名單id作為bitmaps的偏移量,每次訪問和bitmap裡面的id進行比較,如果訪問id不在bitmaps裡面,進行攔截,不允許訪問。
(3)採用布隆過濾器
(4)進行即時的數據監控,發現Redis在命中率急速降低時,排查存取對象和存取數據,設定黑名單。
當使用者要求一個存在的key的資料時,此時redis中該key的資料已經過時,此時若有大量的同時請求發現快取過期都會請求資料來源載入資料並且快取到redis當中,這個時候大量並發可能會把資料庫服務壓垮。
當某個key的數據被大量請求時,這個key就是熱點數據,需要考慮避免「擊穿」問題。
(1)預先設定熱門資料:在redis高峰存取之前,先把一些熱門資料提前存入到redis裡面,加大這些熱門資料key的時長
(2)即時調整:現場監控哪些資料熱門,即時調整key的過期時長
(3)使用鎖定:
就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db。
先使用快取工具的某些帶成功操作回傳值的操作(例如Redis的SETNX)去set一個mutex key
當操作返回成功時,再進行load db的操作,並回設快取,最後刪除mutex key;
當操作返回失敗,證明有線程在load db,當前線程睡眠一段時間再重試整個get快取的方法。
可以對應的資料存在,但是key的數據已經過期(redis快取過期,會自動刪除此key),此時大量的並發請求存取不同的key,即同時大量的存取不同的key,此時key處於過期階段,便會請求資料庫,大量的並發請求會壓垮資料庫伺服器,這種情況稱為快取雪崩,和快取擊穿的不同是前者是一個key。
快取失效時的雪崩效應對底層系統的衝擊非常可怕!
(1) 建構多層快取架構:
#nginx快取redis快取其他快取(ehcache等)
#(2) 使用鎖定或佇列:
用加鎖或佇列的方式保證來保證不會有大量的執行緒對資料庫一次性進行讀寫,從而避免失效時大量的並發請求落在底層儲存系統上。不適用高並發情況
(3) 設定過期標誌更新快取:
(4) 將快取失效時間分散開:
以上是基於Redis快取資料常見的問題如何解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!