Redis之緩存穿透

Redis之緩存穿透

在這里插入圖片描述

文章目錄

  • Redis之緩存穿透
    • 一、什么是緩存穿透?
    • 二、緩存穿透常見的解決方案
      • 1. 緩存空對象(Null Caching)
      • 2. 布隆過濾器(Bloom Filter)?
      • 3. 互斥鎖(Mutex Lock)?
      • 4. 接口層校驗
      • 5. 熱點數據永不過期
      • 6. 緩存預熱
      • 7. 實時監控與限流
      • ☆☆☆組合方案推薦☆☆☆
    • 四、實踐:緩存空對象

一、什么是緩存穿透?

  • 緩存穿透的定義:緩存穿透(Cache Penetration)是指客戶端請求的數據在緩存中和數據庫中都不存在,這樣緩存永遠不會生效,這些請求都會打到數據庫,導致數據庫壓力驟增甚至崩潰。
  • 觸發原因:惡意攻擊、參數偽造、業務邏輯漏洞。
  • 核心問題:大量請求訪問數據庫中不存在的數據,緩存無法攔截。
  • 示例場景:攻擊者發送大量隨機ID查詢商品信息,這些ID在數據庫中不存在,導致每次請求都穿透緩存直達數據庫。
請求未命中
請求未命中
客戶端
Redis
數據庫
  • 與緩存擊穿的區別

    • 緩存擊穿的定義:緩存擊穿(Cache Breakdown)?是指某個熱點key?(如爆款商品信息)在緩存中過期后,大量并發請求同時訪問數據庫(請求數據存在),導致數據庫壓力驟增。
    • ?觸發原因:緩存過期時間到期,且高并發場景下請求集中失效。
    • 核心問題:單個熱點key失效后,大量請求同時訪問數據庫。
    • 示例場景:某明星商品突然爆火,緩存中存儲的商品信息過期后,所有用戶請求同時涌入數據庫查詢。
    維度緩存穿透緩存擊穿
    觸發原因請求不存在的數據熱點key過期后高并發請求
    數據合法性數據本身不存在(非法參數)數據存在但緩存失效(合法參數)
    攻擊性可能是惡意攻擊正常業務高并發
    影響范圍分散的無效請求集中在某個熱點key
    解決方案布隆過濾器、緩存空對象互斥鎖、永不過期、后臺更新

二、緩存穿透常見的解決方案

1. 緩存空對象(Null Caching)

  • 原理: 當查詢數據庫發現數據不存在時,將空結果(如 null)寫入緩存,并設置較短的過期時間。
  • 優點:簡單易實現,直接攔截后續相同請求。
  • 缺點
    • 內存浪費(存儲大量無效 null 值)。
    • 可能出現短時不一致,如:數據已補錄,但緩存未及時失效。(如需強一致性,可以在更新數據時,刪除/覆蓋緩存)
  • 實現
    請求未命中
    請求未命中
    緩存null 設置TTL
    客戶端
    Redis
    數據庫
    public Object getData(String key) {// 1. 查詢緩存Object data = cache.get(key);if (data != null) return data;// 2. 查詢數據庫data = db.query(key);if (data == null) {// 緩存空對象,設置短期過期時間(如5分鐘)cache.set(key, "NULL", 5 * 60);} else // 正常數據設置較長過期時間cache.set(key, data, 60 * 60);}return data;
    }
    

2. 布隆過濾器(Bloom Filter)?

  • 原理:?在緩存層前加布隆過濾器,預先存儲所有合法 Key 的哈希值。查詢時先檢查布隆過濾器:
    • 若返回“不存在”,直接攔截請求。
    • 若返回“可能存在”,繼續查詢緩存/數據庫。
  • 優點:內存占用低(沒有多余的Key),適合海量數據;查詢時間復雜度 O(1)。
  • 缺點
    • 存在誤的可能(可能將不存在判斷為存在)。
    • 實現復雜,刪除元素困難(需重建過濾器)。
  • 適用場景:數據量大且允許誤判(如黑名單校驗)。
  • 實現
    請求
    可能存在,放行
    不存在,拒絕
    命中緩存,返回
    緩存未命中查詢數據庫
    緩存數據
    客戶端
    布隆過濾器
    Redis
    數據庫
    // 初始化布隆過濾器(偽代碼)
    BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(), expectedInsertions);// 數據預熱時加載存在的key
    db.keys().forEach(k -> bloomFilter.put(k));public Object getData(String key) {// 1. 先查布隆過濾器if (!bloomFilter.mightContain(key)) {return null; // 直接攔截不存在的key}// 2. 查詢緩存/數據庫Object data = cache.get(key);if (data == null) {data = db.query(key);cache.set(key, data);}return data;
    }
    

3. 互斥鎖(Mutex Lock)?

  • 原理:緩存未命中時,通過互斥鎖(如 Redis 的 SETNX)保證只有一個線程查詢數據庫,其他線程等待回填緩存。
  • 優點:避免大量請求同時穿透到數據庫。
  • 缺點
    • 分布式環境下需使用分布式鎖(如 Redis RedLock)。
    • 鎖競爭可能成為性能瓶頸。
  • 實現
    存在
    不存在
    用戶請求數據
    緩存中是否存在?
    返回緩存數據
    嘗試獲取互斥鎖
    獲取鎖成功?
    查詢數據庫
    寫入緩存
    釋放鎖
    等待隨機時間
    public Object getData(String key) {Object data = cache.get(key);if (data != null) return data;// 加鎖(如Redis的SETNX)String lockKey = "lock:" + key;if (redis.setnx(lockKey, "1", 10)) { // 10秒鎖超時try {// 二次檢查緩存(防止鎖競爭期間其他線程已加載)data = cache.get(key);if (data != null) return data;data = db.query(key);cache.set(key, data);} finally {redis.del(lockKey); // 釋放鎖}} else {// 等待重試Thread.sleep(100);return getData(key);}return data;
    }
    

4. 接口層校驗

  • 原理:在 API 入口處校驗參數合法性,攔截明顯無效的請求(如非法 ID 格式、負數等)。
  • ?優點:低成本防御惡意攻擊(如掃描全表 ID)。
  • 缺點:無法攔截合法參數但實際不存在的數據請求。
  • 示例:校驗 ID 是否為正整數、長度是否符合預期。
  • 實現
    public ResponseEntity<?> handleRequest(@PathVariable String id) {if (!isValidId(id)) { // 校驗ID合法性return ResponseEntity.badRequest().build();}// 繼續處理業務邏輯
    }
    

5. 熱點數據永不過期

  • 原理:對高頻訪問的熱點數據設置永不過期,通過后臺線程主動更新緩存。
  • 優點:徹底避免緩存失效導致的穿透。
  • 缺點:數據一致性依賴更新機制,需處理臟數據問題。
  • 實現:結合定時任務或事件驅動更新緩存。
    // 緩存寫入時設置永不過期
    cache.set("hot_key", data);// 后臺定時任務刷新數據
    @Scheduled(fixedRate = 300000)
    void refreshHotData() {Object newData = db.query("hot_key");cache.set("hot_key", newData);
    }
    

6. 緩存預熱

  • 原理:在系統啟動或低峰期,預先加載熱點數據到緩存中。
  • ?優點:減少冷啟動時的緩存穿透風險。
  • ?缺點:需提前知道熱點數據(可通過歷史日志分析)。

7. 實時監控與限流

  • 原理:監控異常流量(如大量 null 響應),觸發限流策略(如令牌桶、漏桶算法),保護數據庫。
  • ?優點:兜底防御,避免突發攻擊。
  • ?缺點:需配套監控和告警系統。

☆☆☆組合方案推薦☆☆☆

  • 常規場景:緩存空對象 + 接口參數校驗。
  • 海量數據:布隆過濾器 + 緩存空對象。
  • 高并發熱點數據:永不過期緩存 + 后臺更新線程 + 互斥鎖。

四、實踐:緩存空對象

解決根據id查詢商鋪信息過程中的緩存穿透

命中
不是
未命中
存在
不存在
開始
提交商鋪id
從Redis查詢商鋪緩存
判斷緩存是否命中
判斷是否空值
結束
返回商鋪信息
根據id查詢數據庫
判斷商鋪是否存在
將商鋪數據寫入Redis
將空值寫入Redis
    @Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {// 1.從redis查詢商鋪緩存String key = CACHE_SHOP_KEY + id;String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 判斷命中的是否是空值if(shopJson != null) {// 返回錯誤信息,解決緩存穿透問題return Result.fail("店鋪信息不存在!");}// 4.不存在,根據id查詢數據庫Shop shop = getById(id);if (shop == null) {// 5.數據庫不存在,將空字串寫入Redis,設置過期時間,解決緩存穿透問題stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);// 返回錯誤信息,解決緩存穿透問題return Result.fail("店鋪不存在!");}// 6.存在,寫入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(shop);}

總結:緩存穿透的解決方案需結合業務場景選擇,通常需要多種手段協同(如布隆過濾器攔截非法 Key + 緩存空對象減少數據庫壓力)。同時需權衡內存、一致性和性能,避免過度設計。

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

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

相關文章

【藍橋杯】顏色平衡樹

思路 顏色平衡樹&#xff0c;即子樹中的節點顏色均勻分布。所以要確認一個子樹是否為顏色平衡樹&#xff0c;需要得到它的所有節點的顏色&#xff0c;也就是要深搜它所有的子樹。 這個想法就很標準的啟發式合并了&#xff0c;何為啟發式合并&#xff1f;簡單來說&#xff0c;…

自動化測試工具playwright中文文檔-------14.Chrome 插件

介紹 注意 插件僅在以持久化上下文啟動的 Chrome/Chromium 瀏覽器中工作。請謹慎使用自定義瀏覽器參數&#xff0c;因為其中一些可能會破壞 Playwright 的功能。 以下是獲取位于 ./my-extension 的 Manifest v2 插件背景頁面句柄的代碼示例。 from playwright.sync_api imp…

讓 Python 腳本在后臺持續運行:架構級解決方案與工業級實踐指南

讓 Python 腳本在后臺持續運行&#xff1a;架構級解決方案與工業級實踐指南 一、生產環境需求全景分析 1.1 后臺進程的工業級要求矩陣 維度開發環境要求生產環境要求容災要求可靠性單點運行集群部署跨機房容災可觀測性控制臺輸出集中式日志分布式追蹤資源管理無限制CPU/Memo…

MyBatis 詳解

1. 什么是 MyBatis&#xff1f; MyBatis 是一款優秀的 持久層框架&#xff0c;它通過 XML 或注解配置&#xff0c;將 Java 對象&#xff08;POJO&#xff09;與數據庫操作&#xff08;SQL&#xff09;進行靈活映射&#xff0c;簡化了 JDBC 的復雜操作。 核心思想&#xff1a;S…

循環神經網絡 - 深層循環神經網絡

如果將深度定義為網絡中信息傳遞路徑長度的話&#xff0c;循環神經網絡可以看作既“深”又“淺”的網絡。 一方面來說&#xff0c;如果我們把循環網絡按時間展開&#xff0c;長時間間隔的狀態之間的路徑很長&#xff0c;循環網絡可以看作一個非常深的網絡。 從另一方面來 說&…

GoLand 標紅但程序可正常運行:由符號索引緩存失效引起的假報錯問題

問題描述&#xff1a; 在 GoLand 中&#xff0c;api/tls.go 文件中引用了 api/type.go 中定義的結構體 Options&#xff0c;但 GoLand 把 Options 標紅顯示為未定義&#xff08;undefined symbol&#xff09;&#xff0c;盡管程序實際可以正常編譯和運行&#xff08;go build /…

python-各種文件(txt,xls,csv,sql,二進制文件)讀寫操作、文件類型轉換、數據分析代碼講解

1.文件txt讀寫標準用法 1.1寫入文件 要讀取文件&#xff0c;首先得使用 open() 函數打開文件。 file open(file_path, moder, encodingNone) file_path&#xff1a;文件的路徑&#xff0c;可以是絕對路徑或者相對路徑。mode&#xff1a;文件打開模式&#xff0c;r 代表以…

Uniapp:確認框

目錄 一、 出現場景二、 效果展示三、具體使用 一、 出現場景 在項目的開發中&#xff0c;會經常出現刪除數據的情況&#xff0c;如果直接刪除的話&#xff0c;可能會存在誤刪&#xff0c;用戶體驗不好&#xff0c;所以需要增加一個消息提示&#xff0c;提醒用戶是否刪除。 二…

解密 Vue 打包策略

1. 總體概述 在現代前端開發中&#xff0c;Vue 已成為流行框架之一&#xff0c;開發者通常使用 webpack、vite 或 vue-cli 來構建項目。可能會困惑&#xff1a; 為什么源碼中的資源引用路徑與打包后實際產出的路徑會不一樣&#xff1f;靜態路徑與動態路徑到底如何正確書寫&am…

Golang|接口并發測試和壓力測試

文章目錄 這里出現某些獎品和數據庫中庫存量不一致的問題原因就是在并發的情況下&#xff0c;sync.Map仍然會出現臟寫問題&#xff0c;就是在同時操作下的操作覆蓋問題可以先把數據放到channel里&#xff0c;然后用一個單一的協程負責讀取channel并寫入map

CentOS下,Xftp中文文件名亂碼的處理方式

亂碼原因 中文版Windows默認使用GBK編碼&#xff0c;現代Linux發行版&#xff08;如CentOS、Ubuntu等&#xff09;默認使用UTF-8編碼。Windows下正常的編碼&#xff0c;可能在linux下無法識別&#xff0c;例如&#xff1a;Windows的GBK字節0xD6D0被Linux用UTF-8解碼時&#xf…

解決 Vue 中 input 輸入框被賦值后,無法再修改和編輯的問題

目錄 需求&#xff1a; 出現 BUG&#xff1a; Bug 代碼復現 解決問題&#xff1a; 解決方法1&#xff1a; 解決方法2 關于 $set() 的補充&#xff1a; 需求&#xff1a; 前段時間&#xff0c;接到了一個需求&#xff1a;在選擇框中選中某個下拉菜單時&#xff0c;對應的…

【含文檔+PPT+源碼】基于微信小程序的衛生院預約掛號管理系統的設計與實現

項目視頻介紹&#xff1a; 畢業作品基于微信小程序的衛生院預約掛號管理系統的設計與實現 課程簡介&#xff1a; 本課程演示的是一款基于微信小程序的衛生院預約掛號管理系統的設計與實現&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習…

【Vue】案例——To do list:

【Vue】案例——To do list&#xff1a; 一、案例介紹&#xff1a;二、效果展示&#xff08;如圖&#xff09;三、主要功能&#xff1a;四、技術要點&#xff1a;補充&#xff1a;【Vue】Vue模板語法(點擊可跳轉)補充&#xff1a;【Vue】數據綁定&#xff08;單雙向&#xff09…

導入 .sql 文件到 云服務器上的MySQL中

導入 .sql 文件到 云服務器上的MySQL中 步驟 1&#xff1a;確保 .sql 文件已上傳到云服務器步驟 2&#xff1a;登錄到云服務器步驟 3&#xff1a;檢查文件是否成功傳輸步驟 4&#xff1a;登錄 MySQL步驟 5&#xff1a;創建空數據庫&#xff08;如果尚未創建&#xff09;步驟 6&…

我的機器學習之路(初稿)

文章目錄 一、機器學習定義二、核心三要素三、算法類型詳解1. 監督學習&#xff08;帶標簽數據&#xff09;2. 無監督學習&#xff08;無標簽數據&#xff09;3. 強化學習&#xff08;決策優化&#xff09;(我之后主攻的方向) 四、典型應用場景五、學習路線圖六、常見誤區警示七…

VueDOMPurifyHTML 防止 ??XSS(跨站腳本攻擊)?? 風險

VueDOMPurifyHTML 是一個 ??Vue.js 插件??&#xff0c;用于在 v-html 指令中安全地渲染 HTML 內容&#xff0c;防止 ??XSS&#xff08;跨站腳本攻擊&#xff09;?? 風險。 ??作用?? ??解決 v-html 的安全問題?? Vue 的 v-html 會直接渲染原始 HTML&#xff0…

【數據結構】之散列

一、定義與基本術語 &#xff08;一&#xff09;、定義 散列&#xff08;Hash&#xff09;是一種將鍵&#xff08;key&#xff09;通過散列函數映射到一個固定大小的數組中的技術&#xff0c;因為鍵值對的映射關系&#xff0c;散列表可以實現快速的插入、刪除和查找操作。在這…

How AI could empower any business - Andrew Ng

How AI could empower any business - Andrew Ng References 人工智能如何為任何業務提供支持 empower /?m?pa??(r)/ vt. 授權&#xff1b;給 (某人) ...的權力&#xff1b;使控制局勢&#xff1b;增加 (某人的) 自主權When I think about the rise of AI, I’m reminded …

微服務的服務調用詳解以及常見解決方案對比

微服務服務調用詳解 1. 服務調用分類 服務調用根據通信方式、同步性、實現模式可分為以下類型&#xff1a; 按通信協議分類 類型典型協議/框架特點RPC&#xff08;遠程過程調用&#xff09;Dubbo、gRPC、Apache Thrift高性能、二進制協議、強類型定義HTTP/RESTSpring RestTe…