Redis?常見緩存問題總結(jié)
緩存問題
緩存雪崩
同一時間段內(nèi)大量的熱點 key 全部過期或者 Redis 宕機,所有的請求都打到數(shù)據(jù)庫上
解決方法:
- 給不同的 key 添加不同的 TTL ;
- 利用 Redis 集群提高系統(tǒng)的可用性;
- 當系統(tǒng)故障后,可以啟動服務(wù)熔斷機制,暫停業(yè)務(wù)對外訪問,直接返回錯誤,不讓請求訪問數(shù)據(jù)庫;
緩存穿透
客戶端請求的數(shù)據(jù)在 Redis 和 數(shù)據(jù)庫 中都不存在,這樣的緩存永遠不會生效
解決方法:
- 限制非法的請求,對請求的參數(shù)作檢驗
- 緩存空對象或默認值
- 使用布隆過濾器快速判斷數(shù)據(jù)是否存在,避免通過查詢數(shù)據(jù)庫判斷數(shù)據(jù)是否存在
布隆過濾器
我們在寫入數(shù)據(jù)庫時,在布隆過濾器中做一個標記。業(yè)務(wù)線程確認緩存失效后,去布隆過濾器中查詢該值是否存在,而不用去數(shù)據(jù)庫中進行查詢;
即使發(fā)生了緩存穿透,大量請求只會查詢 Redis 和布隆過濾器,而不會查詢數(shù)據(jù)庫,保證了數(shù)據(jù)庫能正常運行,Redis 自身也是支持布隆過濾器的。
布隆過濾器由三個哈希函數(shù),一個位圖數(shù)組組成:
- 布隆過濾器先將輸入的值通過三個哈希函數(shù)得到相應(yīng)的哈希值;
- 將哈希值對數(shù)組的長度取模,進而得到相應(yīng)的下標;
- 將三個下標設(shè)置為1;
判斷時,布隆過濾器會讀取輸入的值,并通過三個哈希函數(shù)轉(zhuǎn)化成三個數(shù)組下標,然后若三個下標對于值均為1,則該數(shù)據(jù)存在于布隆過濾器中,若有一個為0,則認為該數(shù)據(jù)不存在布隆過濾器中;
所以,布隆過濾器說存在數(shù)據(jù),但實際上該數(shù)據(jù)可能不存在,布隆過濾器說不存在該數(shù)據(jù),則該數(shù)據(jù)真的不存在;
緩存擊穿
某一個熱點 key 過期消失了,大量的請求打到數(shù)據(jù)庫上,數(shù)據(jù)庫很容易被沖垮;
解決方法:
- 使用互斥鎖來更新緩存。當某個線程成功獲取鎖后,進行從數(shù)據(jù)庫中讀取最新的數(shù)據(jù),并把新數(shù)據(jù)存入緩存中去即可,而沒有獲取到鎖的線程進行等待或者返回請求失敗的響應(yīng)即可;
- 不給熱點數(shù)據(jù)添加過期值,該 key 由我們手動刪除;
- 可以在 value 中添加邏輯過期的字段,一旦超過該時間戳就返回舊的值,再去數(shù)據(jù)庫進行更新;
緩存更新問題
緩存更新策略
內(nèi)存淘汰 | TTL 超時 | 主動更新 | |
---|---|---|---|
說明 | 當Redis內(nèi)存達到最大值時,我們可以通過 Redis 的內(nèi)存淘汰策略,淘汰部分的 key | 給每一個key設(shè)置過期時間,到達該過期時間后,該 key 會被自動移除 | 通過業(yè)務(wù)的方法,更新數(shù)據(jù)庫和緩存 |
一致性 | 差 | 一般 | 強 |
維護成本 | 無 | 一般 | 高 |
主動更新
更新數(shù)據(jù)庫和更新緩存的順序問題
- 先更新緩存,再更新數(shù)據(jù)庫
出現(xiàn)了數(shù)據(jù)的不一致,緩存中的數(shù)據(jù)為 b,而數(shù)據(jù)庫中的數(shù)據(jù)為 a
- 先更新數(shù)據(jù)庫,再更新緩存
出現(xiàn)了數(shù)據(jù)的不一致,數(shù)據(jù)庫中的值為 b,而緩存中的值為 a
所以,無論是「先更新數(shù)據(jù)庫,再更新緩存」,還是「先更新緩存,再更新數(shù)據(jù)庫」,這兩個方案都存在并發(fā)問題,當兩個請求并發(fā)更新同一條數(shù)據(jù)的時候,可能會出現(xiàn)緩存和數(shù)據(jù)庫中的數(shù)據(jù)不一致的現(xiàn)象。
更新數(shù)據(jù)庫和刪除緩存的順序問題
這里我們更新數(shù)據(jù)時,不在更新緩存,而是刪除緩存,當讀取不到緩存時,先從數(shù)據(jù)庫中讀取,再寫入緩存;這種叫做旁路緩存策略
寫操作:
- 更新數(shù)據(jù)庫
- 刪除緩存
讀操作:
- 如果命中了緩存,直接返回數(shù)據(jù)
- 如果沒有命中緩存,則從數(shù)據(jù)庫讀取數(shù)據(jù),再寫入緩存
- 先刪除緩存,再更新數(shù)據(jù)庫
此時也出現(xiàn)了數(shù)據(jù)的不一致,緩存中的數(shù)據(jù)為 a,數(shù)據(jù)庫中的數(shù)據(jù)為 b
- 先更新數(shù)據(jù)庫,再刪除緩存
此時也出現(xiàn)了數(shù)據(jù)的不一致,緩存中的數(shù)據(jù)為 a,數(shù)據(jù)庫中的數(shù)據(jù)為 b
但是這種方式出現(xiàn)的幾率會很低,因為更新緩存 a 這步操作是在Redis中進行的,更新數(shù)據(jù)庫為 b 的操作是在數(shù)據(jù)庫中進行的,Redis 中的寫入操作比 數(shù)據(jù)庫中的寫入操作會快很多,所以我們一般采用 更新數(shù)據(jù)庫 + 刪除緩存 的手段
如果強制保存緩存為最新值,可以為緩存的 key 設(shè)置過期時間,如給 a 設(shè)置過期時間,可以作為兜底措施
- 延遲雙刪,針對 先刪除緩存,再更新數(shù)據(jù)庫的情況
偽代碼
刪除緩存 delete(x) 更新數(shù)據(jù) update(x) 睡眠 sleep(N) 再次刪除緩存 delete(x)
前提是:睡眠的時間要比讀請求的過程要大,保證讀請求寫入的緩存要在再次刪除緩存之前,不然再次刪除緩存后還會把舊的值寫入緩存
到此這篇關(guān)于Redis 常見緩存問題總結(jié)的文章就介紹到這了,更多相關(guān)Redis 緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis動態(tài)熱點數(shù)據(jù)緩存策略設(shè)計
本文主要介紹了Redis動態(tài)熱點數(shù)據(jù)緩存策略設(shè)計,包括熱點數(shù)據(jù)識別、動態(tài)緩存、多級緩存、預(yù)加載機制、更新策略以及監(jiān)控告警等,具有一定的參考價值,感興趣的可以了解一下2025-01-01Redis高級數(shù)據(jù)類型Hyperloglog、Bitmap的使用
很多小伙伴在面試中都會被問道 Redis的常用數(shù)據(jù)結(jié)構(gòu)有哪些?可能很大一部分回答都是 string、hash、list、set、zset,但其實還有Hyperloglog和Bitmap,本文就來介紹一下2021-05-05Redis 緩存實現(xiàn)存儲和讀取歷史搜索關(guān)鍵字的操作方法
這篇文章主要介紹了Redis 緩存實現(xiàn)存儲和讀取歷史搜索關(guān)鍵字,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12