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