Redis 緩存三大核心問題:穿透、擊穿與雪崩的深度解析

引言

在現代互聯網架構中,緩存是提升系統性能、降低數據庫壓力的核心手段之一。而 Redis 作為高性能的內存數據庫,憑借其豐富的數據結構、靈活的配置選項以及高效的網絡模型,已經成為緩存領域的首選工具。本文將從 Redis 的基本原理出發,深入探討其在緩存場景中的核心概念、設計模式、常見問題及解決方案,并結合高可用架構的設計思路,幫助讀者全面掌握 Redis 緩存的技術要點。

一、Redis 與緩存的基本原理

1.1 什么是 Redis?

Redis(Remote Dictionary Server)是一個開源的內存鍵值存儲系統,支持多種數據結構(如 String、Hash、List、Set、Sorted Set 等)。它通過內存操作實現極低的延遲(通常為微秒級),同時提供持久化機制和主從復制功能,確保數據的可靠性和高可用性。

1.2 緩存的核心作用

緩存的本質是通過空間換時間,將高頻訪問的數據存儲在內存中,減少對底層數據庫的直接請求。其核心優勢包括:

  • 降低數據庫負載:通過緩存熱點數據,減少數據庫的查詢壓力。
  • 提高響應速度:內存讀取速度遠高于磁盤,顯著縮短請求響應時間。
  • 應對突發流量:在秒殺、促銷等場景中,緩存可以有效吸收瞬時高并發請求。

1.3 緩存的缺點

但是緩存也會增加代碼復雜度和運營的成本:

二、如何使用緩存

實際開發中,會構筑多級緩存來使系統運行速度進一步提升,例如:本地緩存與redis中的緩存并發使用

瀏覽器緩存:主要是存在于瀏覽器端的緩存

應用層緩存:可以分為tomcat本地緩存,比如之前提到的map,或者是使用redis作為緩存

數據庫緩存:在數據庫中有一片空間是 buffer pool,增改查數據都會先加載到mysql的緩存中

CPU緩存:當代計算機最大的問題是 cpu性能提升了,但內存讀寫速度沒有跟上,所以為了適應當下的情況,增加了cpu的L1,L2,L3級的緩存

三、緩存更新策略

3.1 介紹

緩存更新是redis為了節約內存而設計出來的一個東西,主要是因為內存數據寶貴,當我們向redis插入太多數據,此時就可能會導致緩存中的數據過多,所以redis會對部分數據進行更新,或者把他叫為淘汰更合適。

內存淘汰:redis自動進行,當redis內存達到咱們設定的max-memery的時候,會自動觸發淘汰機制,淘汰掉一些不重要的數據(可以自己設置策略方式)

超時剔除:當我們給redis設置了過期時間ttl之后,redis會將超時的數據進行刪除,方便咱們繼續使用緩存

主動更新:我們可以手動調用方法把緩存刪掉,通常用于解決緩存和數據庫不一致問題

3.2 數據庫緩存不一致解決方案:

由于我們的緩存的數據源來自于數據庫,而數據庫的數據是會發生變化的,因此,如果當數據庫中數據發生變化,而緩存卻沒有同步,此時就會有一致性問題存在,其后果是:

用戶使用緩存中的過時數據,就會產生類似多線程數據安全問題,從而影響業務,產品口碑等

綜合考慮我們采用人工編碼方式來解決數據庫和緩存不一致的問題。

????????人工編碼方式:緩存調用者在更新完數據庫后再去更新緩存,也稱之為雙寫方案。

操作緩存和數據庫時有三個問題需要考慮:

刪除緩存還是更新緩存?

  • 更新緩存:每次更新數據庫都更新緩存,無效寫操作較多

  • 刪除緩存:更新數據庫時讓緩存失效,查詢時再更新緩存

如果采用第一個方案,那么假設我們每次操作數據庫后,都操作緩存,但是中間如果沒有人查詢,那么這個更新動作實際上只有最后一次生效,中間的更新動作意義并不大,我們可以把緩存刪除,等待再次查詢時,將緩存中的數據加載出來。

如何保證緩存與數據庫的操作的同時成功或失敗?

  • 單體系統,將緩存與數據庫操作放在一個事務

  • 分布式系統,利用TCC等分布式事務方案

先操作緩存還是先操作數據庫?

  • 先刪除緩存,再操作數據庫

  • 先操作數據庫,再刪除緩存

????????應該具體操作緩存還是操作數據庫,我們應當是先操作數據庫,再刪除緩存,原因在于,如果你選擇第一種方案,在兩個線程并發來訪問時,假設線程1先來,他先把緩存刪了,此時線程2過來,他查詢緩存數據并不存在,此時他寫入緩存,當他寫入緩存后,線程1再執行更新動作時,實際上寫入的就是舊的數據,新的數據被舊數據覆蓋了。

四、緩存穿透:無效請求的“黑洞”

4.1 問題定義

緩存穿透是指請求的數據既不存在于緩存中,也不存在于數據庫中,導致請求直接穿透到數據庫。這種現象會顯著增加數據庫的負載,甚至引發服務不可用。

4.2 常見場景

  • 惡意攻擊:黑客通過偽造非法 ID(如隨機字符串)持續請求,消耗數據庫資源。
  • 業務邏輯漏洞:未校驗用戶輸入的合法性,導致非法請求直接訪問數據庫。
  • 冷啟動數據:新業務上線初期,緩存尚未填充,所有請求均需查詢數據庫。

4.3 解決方案

(1)布隆過濾器(Bloom Filter)
  • 原理:使用位數組和哈希函數快速判斷數據是否存在。
  • 優勢
    • 內存占用極小(如百萬級數據僅需幾 MB)。
    • 攔截效率高(哈希計算時間復雜度為 O(1))。
  • 局限性
    • 存在誤判率(需合理設置哈希函數數量和位數組大小)。
    • 不支持刪除操作(需使用 Counting Bloom Filter)。
(2)緩存空值(Null Caching)
  • 原理:對數據庫中不存在的數據返回空值,并設置短 TTL(如 5 分鐘)。
  • 優勢
    • 實現簡單,無需額外數據結構。
    • 有效攔截惡意請求。
  • 缺點
    • 占用緩存空間(需評估空值占比)。
    • 短時間內可能被高頻請求反復觸發。

緩存空對象思路分析:當我們客戶端訪問不存在的數據時,先請求redis,但是此時redis中沒有數據,此時會訪問到數據庫,但是數據庫中也沒有數據,這個數據穿透了緩存,直擊數據庫,我們都知道數據庫能夠承載的并發不如redis這么高,如果大量的請求同時過來訪問這種不存在的數據,這些請求就都會訪問到數據庫,簡單的解決方案就是哪怕這個數據在數據庫中也不存在,我們也把這個數據存入到redis中去,這樣,下次用戶過來訪問這個不存在的數據,那么在redis中也能找到這個數據就不會進入到緩存了。

布隆過濾:布隆過濾器其實采用的是哈希思想來解決這個問題,通過一個龐大的二進制數組,走哈希思想去判斷當前這個要查詢的這個數據是否存在,如果布隆過濾器判斷存在,則放行,這個請求會去訪問redis,哪怕此時redis中的數據過期了,但是數據庫中一定存在這個數據,在數據庫中查詢出來這個數據后,再將其放入到redis中,

假設布隆過濾器判斷這個數據不存在,則直接返回

這種方式優點在于節約內存空間,存在誤判,誤判原因在于:布隆過濾器走的是哈希思想,只要哈希思想,就可能存在哈希沖突

五、緩存雪崩

????????緩存雪崩是指在同一時段大量的緩存key同時失效或者Redis服務宕機,導致大量請求到達數據庫,帶來巨大壓力。

解決方案:

  • 給不同的Key的TTL添加隨機值

  • 利用Redis集群提高服務的可用性

  • 給緩存業務添加降級限流策略

  • 給業務添加多級緩存

????????

六、緩存擊穿

6.1解決方案

緩存擊穿問題也叫熱點Key問題,就是一個被高并發訪問并且緩存重建業務較復雜的key突然失效了,無數的請求訪問會在瞬間給數據庫帶來巨大的沖擊。

常見的解決方案有兩種:

  • 互斥鎖

  • 邏輯過期

邏輯分析:假設線程1在查詢緩存之后,本來應該去查詢數據庫,然后把這個數據重新加載到緩存的,此時只要線程1走完這個邏輯,其他線程就都能從緩存中加載這些數據了,但是假設在線程1沒有走完的時候,后續的線程2,線程3,線程4同時過來訪問當前這個方法, 那么這些線程都不能從緩存中查詢到數據,那么他們就會同一時刻來訪問查詢緩存,都沒查到,接著同一時間去訪問數據庫,同時的去執行數據庫代碼,對數據庫訪問壓力過大

解決方案一、使用鎖來解決:

因為鎖能實現互斥性。假設線程過來,只能一個人一個人的來訪問數據庫,從而避免對于數據庫訪問壓力過大,但這也會影響查詢的性能,因為此時會讓查詢的性能從并行變成了串行,我們可以采用tryLock方法 + double check來解決這樣的問題。

假設現在線程1過來訪問,他查詢緩存沒有命中,但是此時他獲得到了鎖的資源,那么線程1就會一個人去執行邏輯,假設現在線程2過來,線程2在執行過程中,并沒有獲得到鎖,那么線程2就可以進行到休眠,直到線程1把鎖釋放后,線程2獲得到鎖,然后再來執行邏輯,此時就能夠從緩存中拿到數據了。

解決方案二、邏輯過期方案

方案分析:我們之所以會出現這個緩存擊穿問題,主要原因是在于我們對key設置了過期時間,假設我們不設置過期時間,其實就不會有緩存擊穿的問題,但是不設置過期時間,這樣數據不就一直占用我們內存了嗎,我們可以采用邏輯過期方案。

我們把過期時間設置在 redis的value中,注意:這個過期時間并不會直接作用于redis,而是我們后續通過邏輯去處理。假設線程1去查詢緩存,然后從value中判斷出來當前的數據已經過期了,此時線程1去獲得互斥鎖,那么其他線程會進行阻塞,獲得了鎖的線程他會開啟一個 線程去進行 以前的重構數據的邏輯,直到新開的線程完成這個邏輯后,才釋放鎖, 而線程1直接進行返回,假設現在線程3過來訪問,由于線程線程2持有著鎖,所以線程3無法獲得鎖,線程3也直接返回數據,只有等到新開的線程2把重建數據構建完后,其他線程才能走返回正確的數據。

這種方案巧妙在于,異步的構建緩存,缺點在于在構建完緩存之前,返回的都是臟數據。

6.2 進行對比

互斥鎖方案:由于保證了互斥性,所以數據一致,且實現簡單,因為僅僅只需要加一把鎖而已,也沒其他的事情需要操心,所以沒有額外的內存消耗,缺點在于有鎖就有死鎖問題的發生,且只能串行執行性能肯定受到影響

邏輯過期方案: 線程讀取過程中不需要等待,性能好,有一個額外的線程持有鎖去進行重構數據,但是在重構數據完成前,其他的線程只能返回之前的數據,且實現起來麻煩

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

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

相關文章

耘瞳科技國產化點云處理軟件,開啟智能化三維測量新時代

在現代工業制造領域,三維點云數據已成為推動生產效率提升、質量控制優化以及智能制造轉型的關鍵技術之一。三維點云數據能夠提供高精度的物體表面信息,廣泛應用于制造零件的質量檢測;通過點云數據與CAD模型的對比分析,可以快速檢測…

RabbitMQ面試精講 Day 8:死信隊列與延遲隊列實現

【RabbitMQ面試精講 Day 8】死信隊列與延遲隊列實現 文章標簽 RabbitMQ,消息隊列,死信隊列,延遲隊列,面試技巧,分布式系統 文章簡述 本文是"RabbitMQ面試精講"系列第8天,深入講解死信隊列與延遲隊列的實現原理與實戰應用。文章詳細解析死信隊列的觸發…

團結引擎 1.5.0 版本發布:Android App View 功能詳解

核心亮點 原生安卓應用支持 2D & 3D 雙形態呈現 編輯器全流程集成 靈活調控功能 多應用并行展示 智能座艙應用示例 快速入門指南 開發說明 功能支持 實驗性功能 資源鏈接 團結引擎 1.5.0 版本已于 4 月 14 日正式上線。本次更新中,車機版引入了一項突…

基于SpringBoot的OA辦公系統的設計與實現

文章目錄前言詳細視頻演示具體實現截圖后端框架SpringBoot持久層框架MyBaits成功系統案例:代碼參考數據庫源碼獲取前言 博主介紹:CSDN特邀作者、985高校計算機專業畢業、現任某互聯網大廠高級全棧開發工程師、Gitee/掘金/華為云/阿里云/GitHub等平臺持續輸出高質量…

知識隨記-----用 Qt 打造優雅的密碼輸入框:添加右側眼睛圖標切換顯示

Qt 技巧:通過 QLineEdit 右側眼睛圖標實現密碼可見性切換 文章目錄Qt 技巧:通過 QLineEdit 右側眼睛圖標實現密碼可見性切換概要整體架構流程技術名詞解釋技術細節實現效果展示概要 本文介紹如何使用 Qt 框架為 QLineEdit 控件添加一個右側的眼睛圖標&a…

Unity里的對象旋轉數值跳轉問題的原理與解決方案

文章目錄1. 問題描述2. 問題原因3. 解決方案3.1通過多個父子關系從而控制旋轉(推薦)3.2 使用四元數進行旋轉1. 問題描述 我們現在寫一個3D的Unity程序,我們現在設置了一個物體后,我們想旋轉使其改為我們想要的情況。但是我們如果…

為什么現代 C++ (C++11 及以后) 推薦使用 constexpr和模板 (Templates) 作為宏 (#define) 的替代品??

我們用現實世界的比喻來深入理解??為什么 C 中的宏 (#define) 要謹慎使用,以及為什么現代 C (C11 及以后) 推薦使用 constexpr 和模板 (Templates) 作為替代品。??🧩 ??核心問題:宏 (#define) 是文本替換??想象宏是一個 ??“無腦的…

PyCharm vs. VSCode 到底哪個更好用

在 Python 開發者中,關于 PyCharm 和 VSCode 的討論從未停止。一個是功能齊備的集成開發環境(IDE),另一個是輕快靈活的代碼編輯器。它們代表了兩種不同的開發哲學,選擇哪個,往往取決于你的項目需求、個人習…

FPGA學習筆記——VGA彩條顯示

目錄 一、任務 二、分析 三、代碼 四、實驗現象 五、更新 一、任務 使用VGA實現彩條顯示,模式是640x48060。 二、分析 首先,模式是640x48060,那么對照以下圖標,知道其它信息,不清楚時序和VGA掃描方式的可以看看這…

ES-301A :讓 Modbus 設備無縫接入工業以太網的高效橋梁

在工業自動化領域,串口設備與以太網的互聯互通是提升系統效率的關鍵。ES-301A 工業以太網串口網關作為上海泗博自動化精心打造的專業解決方案,以強大的協議轉換能力、工業級可靠性和靈活配置特性,成為連接 Modbus RTU/ASCII 設備與 Modbus TC…

【學習筆記】FTP庫函數學習

【學習筆記】FTP庫函數學習 FTP基本指令步驟 1、初始化會話句柄:CURL *curl curl_easy_init(); 2、設置會話選項: 設置服務器地址,設置登錄用戶和密碼 curl_easy_setopt(curl, CURLOPT_URL, ftp_server); curl_easy_setopt(curl, CURLOPT_US…

ARM Cortex-M異常處理高級特性詳解

1. 異常處理概述 ARM Cortex-M處理器提供了高效的異常處理機制,包含多種硬件優化特性,顯著提升了中斷響應性能和系統效率。這些特性對于實時嵌入式系統和網絡協議棧(如LwIP)的性能至關重要。 1.1 Cortex-M異常處理架構 Cortex-M異…

【圖像算法 - 08】基于 YOLO11 的抽煙檢測系統(包含環境搭建 + 數據集處理 + 模型訓練 + 效果對比 + 調參技巧)

一、項目背景與需求 【打怪升級 - 08】基于 YOLO11 的抽煙檢測系統(包含環境搭建 數據集處理 模型訓練 效果對比 調參技巧)今天我們使用YOLO11來訓練一個抽煙檢測系統,基于YOLO11的抽煙檢測系統。我們使用了大概兩萬張圖片的數據集訓練了…

vue2升級vue3中v-model的寫法改造

vue2選項式 <template><div><el-rowclass"group-title":title"$t(restore_default_parameters)">{{ $t(restore_default_parameters) }}</el-row><el-form-item :label"$t(restore_default_parameters)" class"…

5G-LEO 簡介

1. 什么是 5G-LEO 5G-LEO 指的是將 5G 新空口&#xff08;5G NR&#xff09;服務擴展到低軌衛星&#xff08;LEO&#xff09;上的非地面網絡&#xff08;NTN, Non-Terrestrial Network&#xff09;方案。通過在距地面約500–2 000 km 的低軌道衛星上部署通信載荷&#xff0c;5G…

【MCAL】AUTOSAR架構下SPI數據同步收發具體實現

目錄 前言 正文 1.依賴的SPI硬件特性 1.1. SPI時隙參數配置 1.2. SPI數據發送和接收模式 2.MCAL中的SPI配置 3.軟件的具體實現 3.1. Spi_SyncTransmit 3.2. Spi_lSyncTransmit 3.3. Spi_lSyncStartJob 3.4. Spi_lSyncTransmitData8Bit 3.5. Spi_lSynTransErrCheck …

SQL157 更新記錄(一)

描述現有一張試卷信息表examination_info&#xff0c;表結構如下圖所示&#xff1a;FiledTypeNullKeyExtraDefaultCommentidint(11)NOPRIauto_increment(NULL)自增IDexam_idint(11)NOUNI(NULL)試卷IDtagchar(32)YES(NULL)類別標簽difficultychar(8)YES(NULL)難度durationint(11…

懸賞任務系統小程序/APP源碼,推薦任務/發布任務/會員服務

1. 我們承諾及優勢本店源碼承諾&#xff1a;1&#xff09;. 店長親測 - 100%完整可運行2&#xff09;. 含詳細安裝文檔3&#xff09;. 支持二次開發定制4&#xff09;. 專業客服隨時解答5&#xff09;. 技術團隊保障質量2. 功能詳細說明主要功能 模塊 角色 解釋說明 用戶登錄和…

Ubuntu20.04系統上使用YOLOv5訓練自己的模型-1

在Ubuntu系統上使用YOLOv5訓練自己的模型&#xff0c;你需要遵循以下步驟。這里我將詳細說明如何從準備數據集到訓練模型的整個過程。 步驟 1: 安裝依賴項 首先&#xff0c;確保你的Ubuntu系統上安裝了Python、PyTorch和必要的庫。你可以使用以下命令安裝這些依賴項&#xff1a…

解決微信小程序中camera組件被view事件穿透觸發對焦以及camera的bindtap事件

view跟camera組件同級 不要用bind:tap和catch:tap 替換用catch:touchstart即可解決&#xff01; 如果你不放心&#xff0c;可以再加個透明蒙版&#xff0c;這樣就不會觸發了&#xff01;&#xff08;不加這個也行&#xff0c;但是必須要用catch:touchstart&#xff09;<!-- …