【Redis】過期鍵刪除策略,LRU和LFU在redis中的實現,緩存與數據庫雙寫一致性問題,go案例


一、Redis 中的過期鍵刪除策略有哪些?

采用了 惰性刪除定期刪除 兩種策略處理過期鍵:

1. 惰性刪除(Lazy Deletion)
  • 機制:只有在訪問 key 時才檢查是否過期,如果已過期則立刻刪除。
  • 優點:對 CPU 資源最友好,只在必要時才處理。
  • 缺點:若 key 過期但始終未被訪問,則不會釋放內存,容易造成空間浪費。

Redis 實現方式:每次訪問前調用 expireIfNeeded() 判斷是否過期,若已過期,Redis 4.0 起還支持 lazyfree_lazy_expire 控制是否異步刪除。

2. 定期刪除(Periodic Deletion)
  • 機制:Redis 每秒默認執行 10 次定期刪除,每次從過期字典中隨機抽取 20 個 key 檢查。

  • 流程

    1. 抽 20 個 key,刪除其中過期的;
    2. 若這 20 個里有超過 25%(即 5 個)過期,則繼續循環;
    3. 每次循環有時間上限,默認 不超過 25ms,防止阻塞主線程。
  • 優點:相較惰性刪除,能主動清理部分過期 key,提升內存利用率;

  • 缺點:受限于檢查頻率和時間,可能存在部分過期 key 無法及時清理的問題。


二、為什么不用定時刪除?

定時刪除(即為每個 key 單獨設置定時器,到期立即刪除)并未被 Redis 實際采用。

  • 優點:能最及時地釋放內存;
  • 缺點:大量 key 會引入大量定時任務極大增加 CPU 開銷,尤其在過期 key 較多時,會嚴重影響 Redis 的性能和響應時間。

三、總結:

Redis 的過期鍵清除策略采用了 惰性刪除 + 定期刪除的組合策略,在保證較低 CPU 開銷的同時,盡可能釋放內存空間

  • 惰性刪除 是只在訪問key的時候檢查是否過期;
  • 定期刪除 定時進行部分key的過期檢查;
  • Redis 放棄了定時刪除,是因為對每個key單獨計時過期刪除,會大大增加cpu負擔

一、什么是 LRU 算法?

LRU,全稱 Least Recently Used,即「最近最少使用」策略,用于在內存滿時淘汰最久未被訪問的鍵

傳統 LRU 的實現方式:

  • 通常使用雙向鏈表 + 哈希表實現;
  • 每次訪問某個 key,就將其移動到鏈表頭部;
  • 淘汰時,從鏈表尾部刪除最舊訪問的 key。

傳統 LRU 的問題:

  1. 維護鏈表需要額外的內存;
  2. 每次訪問都要更新鏈表結構,頻繁的鏈表操作會帶來性能瓶頸

二、Redis 如何實現 LRU?

Redis 沒有使用傳統 LRU,而是實現了近似 LRU,采用“隨機采樣 + 時間戳”方式。

實現細節:

  • Redis 為每個鍵的對象結構添加了 lru 字段,記錄其最近訪問時間(非絕對時間,是一個全局邏輯時鐘)。
  • Redis 每次進行內存淘汰時,并不會遍歷所有鍵,而是從所有鍵中隨機采樣若干個(默認 5 個),然后挑出其中訪問最久遠的鍵淘汰。
  • 這個采樣數量可通過參數 maxmemory-samples 配置。

優點:

  • 無需維護全局鏈表,節省空間;
  • 不需要每次訪問都做鏈表操作,大幅提高性能;
  • 適用于高性能場景的內存淘汰。

缺點:

  • 由于是近似 LRU,并非全局最久未使用的鍵一定會被淘汰,存在一定誤差;
  • 可能出現緩存污染問題:某些鍵被短時間大量訪問后遺留在內存中,卻很少被再次使用。

三、什么是 LFU 算法?(Redis 4.0+ 引入)

LFU,全稱 Least Frequently Used,即「最不常訪問」策略。用于淘汰訪問次數最少的鍵,更能避免短期熱點帶來的緩存污染。

Redis 中 LFU 的實現方式:

  • Redis 在每個鍵中增加了一個 訪問頻率計數器
  • 每次訪問某個 key,會更新其計數;
  • 內存淘汰時,采用類似于近似 LRU 的方式 —— 隨機采樣幾個 key,選擇訪問頻率最少的淘汰

優點:

  • 解決了 LRU 中“只訪問一次卻常駐內存”的問題
  • 更適合處理熱點數據與長尾數據共存的緩存場景。

特性Redis 中的 LRURedis 中的 LFU
全稱Least Recently UsedLeast Frequently Used
淘汰依據最近一次訪問時間被訪問的頻率
實現方式每個 key 保存時間戳 + 隨機采樣每個 key 保存訪問次數 + 隨機采樣
淘汰方式隨機采樣若干 key,淘汰其中最久未訪問的隨機采樣若干 key,淘汰其中訪問最少的
優點高效節省內存能減少緩存污染
典型場景訪問時間分布均勻存在熱點和冷數據

一、四種緩存一致性方案對比表格

編號操作順序是否推薦問題說明
1先更新數據庫 → 后更新緩存并發更新可能將舊值寫入緩存,導致臟數據
2先更新緩存 → 后更新數據庫緩存更新成功但數據庫失敗,導致數據不一致
3先刪除緩存 → 后更新數據庫可避免臟數據寫入緩存,但可能存在緩存空窗期
4先更新數據庫 → 后刪除緩存若刪除緩存失敗,可能導致臟緩存,可使用“延遲雙刪”策略優化

二、推薦方案三:先刪除緩存 → 后更新數據庫

時間線場景:
T1:請求A準備寫操作,刪除緩存
T2:請求B查詢,發現緩存 miss(被 A 刪除了)
T3:請求B 回源數據庫,讀取舊數據(因為 A 還沒更新 DB)
T4:請求B 將舊數據寫入緩存
T5:請求A 將新數據寫入數據庫

問題解決思路:

  • 刪除緩存后寫數據庫,防止更新時緩存被覆蓋
  • 并發下的讀寫覆蓋問題,需要加寫操作保護措施:例如分布式鎖隊列串行化寫
  • 可使用分布式鎖優化并發場景

Go 語言實現(含分布式鎖):

依賴(Redlock 實現分布式鎖):

使用 github.com/bsm/redislock:

go get github.com/bsm/redislock
完整代碼:
package mainimport ("context""fmt""log""time""github.com/bsm/redislock""github.com/redis/go-redis/v9"
)var (ctx        = context.Background()rdb        = redis.NewClient(&redis.Options{Addr: "localhost:6379"})locker     = redislock.New(rdb)
)type UserProfile struct {ID   int64Name string
}// 模擬數據庫操作
func updateUserInDB(userID int64, newData *UserProfile) error {fmt.Printf("DB Updated: userID=%d, data=%+v\n", userID, newData)return nil
}func UpdateUserWithLock(userID int64, newData *UserProfile) error {lockKey := fmt.Sprintf("lock:user:%d", userID)lock, err := locker.Obtain(ctx, lockKey, 5*time.Second, nil)if err != nil {return fmt.Errorf("failed to obtain lock: %w", err)}defer lock.Release(ctx)// 刪除緩存cacheKey := fmt.Sprintf("cache:user:%d", userID)if err := rdb.Del(ctx, cacheKey).Err(); err != nil {log.Printf("failed to delete cache: %v", err)}// 更新數據庫if err := updateUserInDB(userID, newData); err != nil {return fmt.Errorf("failed to update db: %w", err)}return nil
}

三、推薦方案四:先更新數據庫 → 后刪除緩存(延遲雙刪)

時間線場景:
T1:請求A準備更新,先寫數據庫
T2:請求B 查詢緩存,發現存在舊值
T3:請求A 刪除緩存(第一次)
T4:請求B 讀取舊緩存數據并返回
T5:請求B 之后把舊數據重新寫入緩存(或未寫入)
T6:請求A 延遲100ms后再次刪除緩存

問題解決思路:

  • 刪除緩存失敗會導致臟緩存
  • 可采用“延遲雙刪策略”:更新完數據庫后立即刪一次緩存,并延遲一段時間再刪一次

Go 語言實現:

package mainimport ("context""fmt""log""time""github.com/redis/go-redis/v9"
)var (ctx = context.Background()rdb = redis.NewClient(&redis.Options{Addr: "localhost:6379"})
)type UserProfile struct {ID   int64Name string
}// 模擬數據庫操作
func updateUserInDB(userID int64, newData *UserProfile) error {fmt.Printf("DB Updated: userID=%d, data=%+v\n", userID, newData)return nil
}func UpdateUserWithDelayDelete(userID int64, newData *UserProfile) error {// 更新數據庫if err := updateUserInDB(userID, newData); err != nil {return fmt.Errorf("failed to update db: %w", err)}// 刪除緩存cacheKey := fmt.Sprintf("cache:user:%d", userID)if err := rdb.Del(ctx, cacheKey).Err(); err != nil {log.Printf("delete cache failed: %v", err)}// 延遲雙刪(異步)go func() {time.Sleep(100 * time.Millisecond)if err := rdb.Del(ctx, cacheKey).Err(); err != nil {log.Printf("delayed delete failed: %v", err)}}()return nil
}

四、總結

場景推薦方案優點需注意問題與優化點
一般中小型項目方案三實現簡單、延遲可控可用 Redis 鎖優化
高頻寫/對一致性敏感方案四數據庫操作主導、雙刪更穩健需延遲雙刪、監控緩存刪除是否成功
高并發寫入場景方案三+鎖防止并發緩存回寫Redlock 實現需健壯

https://github.com/0voice

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81571.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81571.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81571.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為什么單張表索引數量建議控制在 6 個以內

單張表索引數量建議控制在6個以內的主要原因包括以下幾點?: ?性能影響?:索引會占用額外的磁盤空間。如果索引數量過多,會占用大量的磁盤空間,尤其是在數據量較大的情況下,索引占用的空間可能會超過數據本身。此外&…

深度學習實戰109-智能醫療隨訪與健康管理系統:基于Qwen3(32B)、LangChain框架、MCP協議和RAG技術研發

大家好,我是微學AI,今天給大家介紹一下深度學習實戰109-智能醫療隨訪與健康管理系統:基于Qwen3(32B)、LangChain框架、MCP協議和RAG技術研發。在當今醫療信息化快速發展的背景下,醫療隨訪與健康管理面臨著數據分散、信息整合困難、個性化方案生成效率低等挑戰。傳統的醫療隨…

聊一聊 .NET Dump 中的 Linux信號機制

一:背景 1. 講故事 當 .NET程序 在Linux上崩潰時,我們可以配置一些參考拿到對應程序的core文件,拿到core文件后用windbg打開,往往會看到這樣的一句信息 Signal SIGABRT code SI_USER (Sent by kill, sigsend, raise)&#xff0c…

如何在uniapp H5中實現路由守衛

目錄 Vue3 app.config.globalProperties 1. 創建 Vue 應用實例 2. 添加全局屬性或方法 3. 在組件中使用全局屬性或方法 beforeEach在uniapp的注冊 1、在H5中這兩個對象是都存在的。「router:route」但是功能并不全面,具體可參考下圖。 2、剛剛測試了一下,在微信小程序…

無人機降落傘設計要點難點及原理!

一、設計要點 1. 傘體結構與折疊方式 傘體需采用輕量化且高強度的材料(如抗撕裂尼龍或芳綸纖維),并通過多重折疊設計(如三重折疊縫合)減少展開時的阻力,同時增強局部承力區域的強度。 傘衣的幾何參數&am…

AI時代新詞-AI增強現實(AI - Enhanced Reality)

一、什么是AI增強現實(AI - Enhanced Reality)? AI增強現實(AI - Enhanced Reality)是指將人工智能(AI)技術與增強現實(Augmented Reality,簡稱AR)技術相結合…

基于Matlab實現各種光譜數據預處理

在IT領域,尤其是在數據分析和科學研究中,光譜數據的預處理是至關重要的步驟。光譜數據通常包含了豐富的信息,但往往受到噪聲、雜散光、背景信號等因素的影響,需要通過預處理來提取有效信號,提高分析的準確性和可靠性。…

用 commitizen-go 來實現標準化你的Git提交信息 【windows 版】

前言 團隊中有部分人的 commit 信息比較隨意,因此想用工具來進行約束, web 項目可以使用 commitizen 來實現, 但是 golang 又該用什么來約束呢, 在 Github 上找到 commitizen-go 可以做為 commitizen 平替,但該說明文…

為什么共現矩陣是高維稀疏的

為什么共現矩陣是高維稀疏的? 共現矩陣(Co-occurrence Matrix)的高維稀疏性是其固有特性,主要由以下原因導致: 1. 高維性的根本原因 詞匯表大小決定維度: 共現矩陣的維度為 ( V \times V ),其…

OpenLayers 加載鼠標位置控件

注:當前使用的是 ol 5.3.0 版本,天地圖使用的key請到天地圖官網申請,并替換為自己的key 地圖控件是一些用來與地圖進行簡單交互的工具,地圖庫預先封裝好,可以供開發者直接使用。OpenLayers具有大部分常用的控件&#x…

知識宇宙-學習篇:學編程為什么從C語言開始學起?

名人說:博觀而約取,厚積而薄發。——蘇軾《稼說送張琥》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder😊) 目錄 一、C語言的歷史地位與影響力1. 編程語言的"鼻祖"2. 現代技術的基礎 二、…

手機IP地址更換的影響與操作指南

在移動互聯網時代,IP地址如同手機的“網絡身份證”,其變更可能對上網體驗、隱私安全及服務訪問產生連鎖反應。無論是為了繞過地域限制、保護隱私,還是解決網絡沖突,了解IP更換的影響與正確操作方法都至關重要。本文將系統分析影響…

基于Alibaba Cloud Linux + 寶塔面板安裝 LibreOffice 全攻略流程

LibreOffice 是一款功能強大的辦公軟件,默認使用開放文檔格式 (OpenDocument Format , ODF), 并支持 *.docx, *.xlsx, *.pptx 等其他格式。 官網:https://www.libreoffice.org/ 或 https://zh-cn.libreoffice.org/ Alibaba Cloud Linux 3(Soaring Falcon) 是阿里云自主研發…

UniApp 微信小程序綁定動態樣式 :style 避坑指南

在使用 UniApp 開發跨端應用時,綁定動態樣式 :style 是非常常見的操作。然而,很多開發者在編譯為 微信小程序 時會遇到一個奇怪的問題: 原本在 H5 中可以正常渲染的樣式,在微信小程序中卻不生效! 讓我們通過一個示例來…

WebSocket學習總結

WebSocket 是一種基于TCP的網絡通信協議,允許瀏覽器和服務器之間進行全雙工、實時、低延遲的雙向數據傳輸。它突破了傳統HTTP協議的限制(請求-響應模式),特別適合需要實時通信的場景(如聊天、實時數據推送、游戲等&…

【screen-recorder-tts】RPG 游戲字幕語音實時合成,讓無聲文字游戲變有聲

screen-recorder-tts RPG 游戲字幕語音實時合成,讓無聲文字游戲變有聲! 歡迎大佬們提 PR,一起完善這個項目!!! Real-time TTS for RPG game subtitles, turning silent text games into audio experienc…

深入解析Spring Boot與Redis的緩存集成實踐

深入解析Spring Boot與Redis的緩存集成實踐 引言 在現代Web應用中,緩存技術是提升系統性能的重要手段之一。Redis作為一種高性能的內存數據庫,廣泛應用于緩存場景。本文將詳細介紹如何在Spring Boot項目中集成Redis,并探討其在實際開發中的…

4月報 | SeaTunnel支持TDengine的多表Sink功能

各位熱愛 Apache SeaTunnel 的小伙伴們,今年 4 月份月報更新啦!這里將記錄 SeaTunnel 社區每月的重要更新,歡迎關注! 在本月的眾多更新中,最令人關注的一項新特性是——TDengine 多表 Sink 功能的支持(由 …

vue項目表格甘特圖開發

?? 甘特圖可以管理項目進度,生產進度等信息,管理者可以更直觀的查看內容。 1. 基礎環境搭建 引入 dhtmlx-gantt 插件引入插件樣式 dhtmlxgantt.css引入必要的擴展模塊(如 markers、tooltip)創建 Vue 組件并掛載 DOM 容器初始化 gantt 圖表配置2. 數據準備與處理 定義任務…

華為HCIP-Cloud-Service認證H13-821V2.0-002

1.以下關于 HiLens 關鍵能力的說法錯誤的是?(C) A.HiLens 能提供模型優化框架、自動壓縮模型能力,將模型轉換為目標芯片所支持的模 型格式 B.在 HLens 平臺上開發的 Ski11 可以運行到任何基于華為海思芯片的設備上 C.HilLens 平臺只能導入從…