利用互斥鎖或者利用邏輯過期解決緩存擊穿問題


緩存擊穿問題概述

緩存擊穿是指某個 熱點數據緩存過期 時,大量并發請求直接穿透緩存,同時訪問數據庫,導致數據庫壓力驟增甚至崩潰。以下是基于 互斥鎖邏輯過期 的解決方案:


一、緩存擊穿的核心原因

  • 熱點數據失效:高并發場景下,某個熱點數據的緩存突然過期,導致瞬時大量請求繞過緩存直接訪問數據庫。
  • 無緩存保護:緩存未設計有效機制應對突發性并發穿透。

二、解決方案 1:互斥鎖(Mutex Lock)

核心思想

當緩存失效時,僅允許一個線程查詢數據庫并重建緩存,其他線程阻塞等待,避免并發穿透。

實現步驟(以 Redis 分布式鎖為例)
  1. 查詢緩存
    檢查緩存是否存在,若存在則直接返回數據。

    def get_data(key):data = redis.get(key)if data is not None:return data# 緩存未命中,嘗試加鎖return get_data_via_mutex(key)
    
  2. 獲取分布式鎖
    使用 Redis 的 SETNX(或 Redlock 算法)實現分布式鎖,確保原子性。

    def acquire_lock(lock_key, expire=10):# 生成唯一標識(如UUID),避免誤刪其他線程的鎖identifier = str(uuid.uuid4())if redis.set(lock_key, identifier, nx=True, ex=expire):return identifierreturn None
    
  3. 查詢數據庫并重建緩存
    只有獲取鎖的線程執行數據庫查詢,其他線程等待。

    def get_data_via_mutex(key):lock_key = f"lock:{key}"identifier = acquire_lock(lock_key)if not identifier:# 未獲取鎖,短暫等待后重試time.sleep(0.1)return get_data(key)try:# 再次檢查緩存(可能已被其他線程更新)data = redis.get(key)if data:return data# 查詢數據庫data = db.query("SELECT * FROM table WHERE key=?", key)# 寫入緩存redis.setex(key, 3600, data)finally:# 釋放鎖(需原子性操作)release_lock(lock_key, identifier)return data
    
  4. 釋放鎖
    使用 Lua 腳本確保原子性釋放鎖:

    -- KEYS[1]=lock_key, ARGV[1]=identifier
    if redis.call("get", KEYS[1]) == ARGV[1] thenreturn redis.call("del", KEYS[1])
    elsereturn 0
    end
    
優缺點
  • 優點:強一致性,徹底避免緩存擊穿。
  • 缺點:性能有損耗(線程需等待鎖),鎖超時時間需合理設置(過長影響并發,過短可能死鎖)。

三、解決方案 2:邏輯過期(Logical Expiration)

核心思想

緩存數據不依賴物理過期時間,而是在數據中存儲邏輯過期時間。當數據過期時,由單個線程異步更新緩存,其他線程繼續返回舊數據。

實現步驟
  1. 緩存數據結構設計
    在緩存中存儲邏輯過期時間(expire_time)和實際數據:

    {"data": "真實數據","expire_time": 1715000000  // 邏輯過期時間戳
    }
    
  2. 查詢緩存
    檢查邏輯過期時間,若未過期則直接返回數據。

    def get_data(key):cache_data = redis.get(key)if cache_data:data_obj = json.loads(cache_data)if data_obj["expire_time"] > time.time():return data_obj["data"]else:# 觸發異步更新async_refresh_cache(key)return data_obj["data"]  # 返回舊數據else:# 緩存完全不存在(需初始化)return load_data_and_init_cache(key)
    
  3. 異步更新緩存
    使用互斥鎖或標記位,確保僅一個線程執行數據庫查詢。

    def async_refresh_cache(key):lock_key = f"refresh_lock:{key}"if redis.set(lock_key, 1, nx=True, ex=10):try:# 查詢數據庫new_data = db.query("SELECT * FROM table WHERE key=?", key)# 更新邏輯過期時間(例如延長1小時)new_expire_time = time.time() + 3600cache_obj = {"data": new_data, "expire_time": new_expire_time}redis.setex(key, 3600 * 24, json.dumps(cache_obj))  # 物理過期時間更長finally:redis.delete(lock_key)
    
  4. 初始化緩存
    若緩存完全不存在(如服務重啟),直接加載數據:

    def load_data_and_init_cache(key):# 加鎖防止并發初始化lock_key = f"init_lock:{key}"identifier = acquire_lock(lock_key)if not identifier:time.sleep(0.1)return get_data(key)try:# 再次檢查緩存cache_data = redis.get(key)if cache_data:return json.loads(cache_data)["data"]# 查詢數據庫并寫入緩存data = db.query("SELECT * FROM table WHERE key=?", key)expire_time = time.time() + 3600cache_obj = {"data": data, "expire_time": expire_time}redis.setex(key, 3600 * 24, json.dumps(cache_obj))return datafinally:release_lock(lock_key, identifier)
    
優缺點
  • 優點:高并發性能好,用戶無感知短暫延遲。
  • 缺點:數據可能短暫不一致,需業務容忍舊數據。

四、方案對比與選型

方案適用場景一致性性能實現復雜度
互斥鎖強一致性要求(如金融交易)強一致性較低
邏輯過期高并發、允許短暫不一致最終一致性

五、增強策略

  1. 結合兩種方案

    • 在邏輯過期的基礎上,若異步更新失敗,可降級為互斥鎖同步更新。
  2. 熔斷機制

    • 當數據庫壓力過大時,觸發熔斷,直接返回默認值或錯誤頁。
  3. 預熱緩存

    • 提前加載熱點數據,避免緩存突然過期。

六、注意事項

  1. 鎖超時時間

    • 互斥鎖的超時時間需略大于數據庫查詢時間,避免鎖提前釋放導致多個線程同時更新。
  2. 緩存雪崩防護

    • 為不同 Key 設置隨機過期時間,避免大量緩存同時失效。
  3. 邏輯過期時間維護

    • 異步更新失敗時,需記錄日志并告警,防止緩存長期不更新。

通過合理選擇互斥鎖或邏輯過期方案,可有效解決緩存擊穿問題,保障系統的高可用性與穩定性。

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

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

相關文章

Vue3組合式API內核解析:從原子狀態到企業級架構

一、組合邏輯原子化設計 1.1 狀態管理層級拓撲 1.2 組合單元類型對照表 類型典型實現適用場景復用維度UI邏輯單元useForm/useTable表單/列表交互100%跨項目復用業務邏輯單元useOrderFlow訂單流程控制同項目跨模塊設備能力單元useGeolocation地理位置獲取跨技術棧復用狀態管理…

新生宿舍管理系統

收藏關注不迷路!! 🌟文末獲取源碼數據庫🌟 感興趣的可以先收藏起來,還有大家在畢設選題(免費咨詢指導選題),項目以及論文編寫等相關問題都可以給我留言咨詢,希望幫助更多…

從零上手GUI Guider學習LVGL——Button

視頻教程請關注我b站:同學_好好學習,這里只是做相應的筆記文稿 從零上手GUI Guider學習LVGL——Buttton 前言: 首先我們為什么要學習LVGL設計工具呢? 1 降低開發難度 2 提高開發效率 所以我們需要學習一款合適的設計工具 在b站很少…

【AAOS】【源碼分析】Car UX Restrictions

AAOS UX的核心理念:安全駕駛是駕駛員的首要責任。汽車制造商和應用程序開發人員的所有設計都必須反映這一優先事項。 AAOS平臺允許設備制造商(OEM)對不同駕駛狀態下的限制進行定制。 駕駛員分心指南 只有符合Driver Distraction Guidelines的應用才可以在駕駛過程中運行。…

jvm調優工具arthas(阿爾薩斯)安裝與使用---實踐

jvm調優工具arthas(阿爾薩斯)安裝與使用—實踐 Arthas 是Alibaba開源的Java診斷工具,深受開發者喜愛。 當你遇到以下類似問題而束手無策時,Arthas可以幫助你解決: 這個類從哪個 jar 包加載的?為什么會報各種類相關的 Exception…

機器學習期末

選擇題 以下哪項不是機器學習的類型? A. 監督學習 B.無監督學習 C.半監督學習 D.全監督學習 D 哪一個是機器學習的合理定義? A、機器學習是計算機編程的科學 B、機器學習從標記的數據中學習 C、機器學習是允許機器人智能行動的領域 D、機器學習能使計算機能夠在…

3DMAX粒子流樣條線生成器PFSpliner使用方法詳解

3DMAX粒子流樣條線生成器,是一款功能強大且富有創意的工具。它能夠為“粒子流源”的每一個粒子生成專屬的動畫樣條線,這些樣條線描繪出粒子在空間中的運動軌跡,就如同為粒子繪制出了一條條獨特的“運動地圖”。更為出色的是,這些樣…

Maven中clean、compil等操作介紹和Pom.xml中各個標簽介紹

文章目錄 前言Maven常用命令1.clean2.vaildate3.compile4.test5.package6.verify7.install8.site9.deploy pom.xml標簽詳解格式<?xml version"1.0" encoding"UTF-8"?>(xml版本和編碼)modelVersion&#xff08;xml版本&#xff09;groupId&#xff…

Centos7.6安裝JDK 1.8教程

前提&#xff1a;先把jdk1.8文件上傳到usr/local目錄下&#xff0c;文件名如&#xff1a;jdk-8u151-linux-x64.tar.gz 1. 解壓 JDK 壓縮包 假設 jdk-8u151-linux-x64.tar.gz 文件位于 /usr/local 目錄下。 進入 /usr/local 目錄&#xff1a; cd /usr/local 解壓文件&#…

EuroCropsML:首個面向少樣本時間序列作物分類的多國基準數據集

2025-04-15&#xff0c;由慕尼黑工業大學等機構創建的 EuroCropsML 數據集&#xff0c;這是一個結合了農民報告的作物數據與 Sentinel-2 衛星觀測的時間序列數據集&#xff0c;覆蓋了愛沙尼亞、拉脫維亞和葡萄牙。該數據集為解決遙感應用中作物類型數據空間不平衡問題提供了新的…

將python項目打包成Windows后臺服務

前文,我開發了一個基于windows11與本地deepseek實現的語音助手,之前是通過CMD直接執行項目的main.py文件。但是這樣不適合移植,現在想將其生成一個exe文件,以及部署成windows的后臺服務。 關于語音助手的開發與發布,可以看的CSDN文章:一個基于windows11與本地deepseek實…

yolov8復現

Yolov8的復現流程主要包含環境配置、下載源碼和驗證環境三大步驟&#xff1a; 環境配置 查看電腦狀況&#xff1a;通過任務管理器查看電腦是否有獨立顯卡&#xff08;NVIDIA卡&#xff09;。若有&#xff0c;后續可安裝GPU版本的pytorch以加速訓練&#xff1b;若沒有&#xff0…

Yocto項目實戰教程 · 第4章:4.1小節元數據

&#x1f50d; B站相應的視頻教程&#xff1a; &#x1f4cc; Yocto項目實戰教程-第4章-4.1小節-元數據 記得三連&#xff0c;標為原始粉絲。 在嵌入式Linux系統構建中&#xff0c;Yocto項目憑借其高度模塊化、可配置的特性成為主流工具。而其背后的關鍵支撐之一&#xff0c;便…

《AI大模型應知應會100篇》第23篇:角色扮演技巧:讓AI成為你需要的專家

第23篇&#xff1a;角色扮演技巧&#xff1a;讓AI成為你需要的專家 摘要 在當今人工智能快速發展的時代&#xff0c;大模型已經不僅僅是簡單的問答工具&#xff0c;它們可以通過角色扮演技巧模擬各類專家身份&#xff0c;從而為用戶提供更專業、更有針對性的服務。本文將深入探…

Windows系統安裝RustDesk Server的詳細步驟和客戶端設置

Windows系統安裝RustDesk Server的詳細步驟 在Windows系統上安裝RustDesk Server涉及幾個關鍵步驟,包括安裝必要的依賴、下載RustDesk Server程序、配置并啟動服務。以下是詳細的步驟: 1. 安裝Node.js和PM2 RustDesk Server的某些版本可能需要Node.js環境來運行,而PM2是一…

如何實現一個構造函數繼承另一個構造函數的屬性和方法?給出ES5和ES6兩種方式

在 JavaScript 中&#xff0c;構造函數繼承可以通過 原型鏈 和 構造函數調用 實現。以下是 ES5 和 ES6 的實現方式&#xff1a; ES5 實現方式 關鍵步驟 繼承實例屬性&#xff1a;在子構造函數中調用父構造函數的 call/apply&#xff0c;綁定 this。繼承原型方法&#xff1a;將…

AWS Redshift的使用場景及一些常見問題

Redshift 不是關系型數據庫, 提供了Amazon Redshift Serverless 和 Amazon Redshift 都是構建于 Redshift 數倉引擎之上的&#xff0c;但它們適用的場景不同。Redshift和Dynamodb都可以存儲數據, 分別怎么選擇? 這里記錄一些常見的問題和場景。 1. 如何選擇用Amazon Redshift…

十五種光電器件綜合對比——《器件手冊--光電器件》

十五、光電器件 名稱 原理 特點 應用 發光二極管&#xff08;LED&#xff09; 基于半導體材料的電致發光效應&#xff0c;當電流通過時&#xff0c;電子與空穴復合&#xff0c;釋放出光子。 高效、節能、壽命長、響應速度快、體積小。 廣泛用于指示燈、照明、顯示&#…

Electricity Market Optimization(VI) - 機組組合模型以及 Gurobi 求解

本文參考鏈接&#xff1a;link \hspace{1.6em} 機組組合問題在電力系統中非常重要&#xff0c;這個問題也是一個優化問題&#xff0c;研究的就是如何調度現有的機組&#xff0c;調度的對象是以煤炭、石油、天然氣為燃料的火力發電機以及水力發電機等可預測處理的發電機組&#…

linux多線(進)程編程——(8)多進程的沖突問題

前言 隨著時間的推移&#xff0c;共享內存已經在修真界已經淪為禁術。因為使用這種方式溝通的兩人往往會陷入到走火入魔的狀態&#xff0c;思維扭曲。進程君父子見到這種情況&#xff0c;連忙開始專研起來&#xff0c;終于它們發現了共享內存存在的問題&#xff1a; 進程間沖…