Redis 延遲雙刪的實(shí)現(xiàn)示例
延遲雙刪(Delayed Double Deletion) 是在 Cache-Aside 基礎(chǔ)上,為了解決"并發(fā)讀寫導(dǎo)致緩存回填舊值"問題而設(shè)計(jì)的方案。
一、問題背景:為什么需要雙刪?
先看單刪的問題場(chǎng)景(先刪緩存,再更新DB):
時(shí)間點(diǎn) 線程A(寫) 線程B(讀)
t1 刪除緩存
t2 查詢緩存(未命中)
t3 查詢數(shù)據(jù)庫 → 得到舊值
t4 更新數(shù)據(jù)庫為新值
t5 將舊值寫入緩存 ← 緩存變臟!
即使你先更新DB再刪緩存,也有類似風(fēng)險(xiǎn):
時(shí)間點(diǎn) 線程A(寫) 線程B(讀)
t1 更新數(shù)據(jù)庫
t2 查詢數(shù)據(jù)庫 → 得到舊值(因主從延遲等)
t3 刪除緩存
t4 將舊值寫入緩存 ← 緩存變臟!
延遲雙刪的核心思想:等一等,讓并發(fā)的讀請(qǐng)求都結(jié)束了,再把緩存清掉。
二、延遲雙刪的具體步驟
1. 先刪除緩存
2. 更新數(shù)據(jù)庫
3. 休眠/等待一段時(shí)間(比如 200ms~1s)
4. 再次刪除緩存
用代碼表示:
import time
def update_with_delayed_double_deletion(key, new_value):
# 第一次刪緩存
redis.delete(key)
# 更新數(shù)據(jù)庫
db.update(key, new_value)
# 延遲一段時(shí)間(關(guān)鍵?。?
time.sleep(0.5) # 500ms,根據(jù)業(yè)務(wù)調(diào)整
# 第二次刪緩存(把可能回填的舊值清掉)
redis.delete(key)三、延遲時(shí)間怎么定?
這是最關(guān)鍵的參數(shù),定太短沒效果,定太長影響性能。
建議公式:
延遲時(shí)間 ≈ 主從同步延遲 + 業(yè)務(wù)讀操作耗時(shí) + 冗余緩沖
- 主從同步延遲:如果有主從架構(gòu),通常 100ms~500ms
- 業(yè)務(wù)讀操作耗時(shí):查詢DB + 序列化 + 網(wǎng)絡(luò)往返
- 冗余緩沖:再加 100~200ms 保險(xiǎn)
實(shí)際建議:
- 無主從:100~300ms
- 有主從:300~800ms
- 高并發(fā)場(chǎng)景:可以動(dòng)態(tài)調(diào)整,或根據(jù)監(jiān)控?cái)?shù)據(jù)優(yōu)化
四、第二次刪除失敗怎么辦?
如果第二次刪緩存時(shí) Redis 掛了或網(wǎng)絡(luò)抖動(dòng),緩存還是會(huì)臟。
解決方案:引入異步重試
import threading
def update_with_retry(key, new_value):
# 第一次刪 + 更新DB
redis.delete(key)
db.update(key, new_value)
# 延遲后異步執(zhí)行第二次刪除
def delayed_delete():
time.sleep(0.5)
try:
redis.delete(key)
except Exception:
# 失敗則放入重試隊(duì)列(MQ 或本地延遲隊(duì)列)
retry_queue.put(key)
threading.Thread(target=delayed_delete).start()更生產(chǎn)化的做法是用 消息隊(duì)列 或 延遲任務(wù)框架(如 Celery、XXL-Job)來做第二次刪除,確??煽繄?zhí)行。
五、完整流程圖
寫請(qǐng)求到來
│
▼
┌─────────────┐
│ 刪除緩存 │?── 第一次刪除,清掉舊值
└─────────────┘
│
▼
┌─────────────┐
│ 更新數(shù)據(jù)庫 │
└─────────────┘
│
▼
┌─────────────┐
│ 延遲等待 │?── 等并發(fā)讀請(qǐng)求結(jié)束,舊值回填完成
└─────────────┘
│
▼
┌─────────────┐
│ 再次刪除緩存 │?── 第二次刪除,清掉可能回填的舊值
│ (帶重試) │
└─────────────┘
│
▼
結(jié)束
六、優(yōu)缺點(diǎn)總結(jié)
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 實(shí)現(xiàn)簡(jiǎn)單,不引入額外組件 | 延遲等待會(huì)阻塞寫請(qǐng)求(或用異步) |
| 能有效降低緩存不一致概率 | 延遲時(shí)間不好精確估算 |
| 兼容現(xiàn)有 Cache-Aside 架構(gòu) | 極端高并發(fā)下仍可能有小概率不一致 |
七、適用場(chǎng)景
- 讀多寫少:寫操作不頻繁,延遲等待的開銷可接受
- 允許秒級(jí)最終一致:不要求實(shí)時(shí)強(qiáng)一致
- 無主從或主從延遲可控:延遲時(shí)間能估算得準(zhǔn)
八、一句話總結(jié)
延遲雙刪 = "先刪緩存 → 更新DB → 等一會(huì)兒 → 再刪一次",用"等一等"來覆蓋并發(fā)讀回填舊值的時(shí)間窗口。
到此這篇關(guān)于Redis 延遲雙刪的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Redis 延遲雙刪內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)每日簽到功能(大數(shù)據(jù)量)
在面對(duì)百萬級(jí)用戶簽到情況下,傳統(tǒng)數(shù)據(jù)庫存儲(chǔ)和判斷會(huì)遇到瓶頸,使用Redis的二進(jìn)制數(shù)據(jù)類型可實(shí)現(xiàn)高效的簽到功能,示例代碼展示了如何調(diào)用這些功能,包括當(dāng)天簽到、補(bǔ)簽以及查詢簽到記錄,PHP結(jié)合Redis二進(jìn)制數(shù)據(jù)類型可有效處理大數(shù)據(jù)量下的簽到問題2024-10-10
Redis?Server啟動(dòng)過程的詳細(xì)步驟
本文主要介紹了Redis?Server啟動(dòng)過程的詳細(xì)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Redis實(shí)現(xiàn)集群搭建+集群讀寫的示例
本文介紹了Redis集群的搭建和讀寫操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02
redis批量刪除namespace下的數(shù)據(jù)的實(shí)現(xiàn)步驟
在開發(fā)中為了更好的管理數(shù)據(jù),對(duì)redis進(jìn)行了分組存儲(chǔ)操作,在存值時(shí)加了命名空間來實(shí)現(xiàn),本文就來介紹一下redis批量刪除namespace下的數(shù)據(jù)的實(shí)現(xiàn)步驟,感興趣的可以了解一下2025-12-12
Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn)方法
這篇文章主要介紹了Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Redis遠(yuǎn)程連接Redis客戶端的實(shí)現(xiàn)步驟
本文主要介紹了Redis遠(yuǎn)程連接Redis客戶端的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
redis服務(wù)器允許遠(yuǎn)程主機(jī)訪問的方法
今天小編就為大家分享一篇redis服務(wù)器允許遠(yuǎn)程主機(jī)訪問的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-05-05

