Redis7——進階篇(五)

?前言:此篇文章系本人學習過程中記錄下來的筆記,里面難免會有不少欠缺的地方,誠心期待大家多多給予指教。


基礎篇:

  1. Redis(一)
  2. Redis(二)
  3. Redis(三)
  4. Redis(四)
  5. Redis(五)
  6. Redis(六)
  7. Redis(七)
  8. Redis(八)

進階篇:

  1. Redis(九)
  2. Redis(十)
  3. Redis(十一)
  4. Redis(十二)

接上期內容:上期完成了相關案例的學習。下面學習緩存穿透、預熱、雪崩、擊穿,話不多說,直接發車。


一、緩存預熱

(一)、定義

緩存預熱是一種在系統啟動階段或者特定時間點,將一些經常訪問或者關鍵的數據提前加載到緩存中的操作,以減少對數據源(如數據庫)的訪問次數,從而提高系統的響應速度和性能。避免在用戶首次請求時才去加載數據而導致的性能延遲。


(二)、功能

  1. 減少首次請求延遲:當用戶首次訪問某些數據時,如果沒有進行緩存預熱,系統需要從數據庫等數據源中查詢數據,這個過程可能會比較耗時。
  2. 減輕數據庫壓力:在系統運行初期,如果大量用戶同時發起請求,這些請求都直接訪問數據庫,會給數據庫帶來巨大的壓力,甚至可能導致數據庫性能下降或者崩潰。緩存預熱可以將部分數據提前加載到緩存中,后續的請求優先從緩存中獲取數據,從而減少了對數據庫的訪問頻率,降低了數據庫的負載
  3. 提高系統性能和穩定性:由于緩存的讀寫速度通常比數據庫等數據源快很多,緩存預熱可以讓系統在處理請求時更快地獲取數據,從而提高系統的整體性能。同時,減少了對數據庫的依賴,降低了因數據庫故障或性能問題導致系統不可用的風險,增強了系統的穩定性。

(三)、常用方案

  1. ?硬編碼(不大推薦):在代碼中直接明確地指定需要加載到緩存的數據和邏輯,不通過外部配置或動態計算來改變。在系統啟動時,按照預先編寫好的代碼邏輯將數據加載到緩存中。
  2. @PostConstruct注解:?Java 中的一個注解,用于標記一個方法,該方法會在依賴注入完成之后、對象正式投入使用之前被自動調用。
  3. 定時器任務:通過定時任務框架(如 Spring 的@Scheduled注解、Quartz 等),按照預設的時間間隔(如每天凌晨、每小時等)自動執行緩存預熱操作。
  4. 數據腳本:使用腳本語言(如 Python、Shell 等)編寫腳本,通過腳本連接到緩存系統,將數據加載到緩存中。?

二、緩存雪崩

(一)、名詞解釋

緩存雪崩是指在某一時刻,緩存中大量的鍵在同一時間點或者在極短的時間內集中過期失效,或者緩存服務器發生故障導致緩存服務不可用,此時大量原本可以從緩存中獲取數據的請求,都直接涌向了數據庫等后端數據源,給數據庫帶來巨大的壓力,甚至可能導致數據庫不堪重負而崩潰,進而使整個系統出現性能急劇下降、服務不可用等嚴重問題。


(二)、發生場景

1、硬件方面

緩存服務器的硬件設備(如硬盤、內存、網卡等)出現故障,可能會導致緩存服務無法正常運行,從而發生緩存雪崩現象。


2、業務方面

大量的業務key同時過期,比如在進行緩存預熱時,為大量緩存數據設置了相同的過期時間,當這個過期時間到達時,這些緩存數據會同時失效,從而引起緩存雪崩現象。


(三)、預防與解決措施

硬件方面無法把控,主要從業務方面來解決。

業務方面:

  1. 避免大量緩存鍵同時過期:①、設置隨機時間:在設置緩存鍵的過期時間時,為每個鍵的過期時間添加一個隨機的偏移量,避免它們集中在同一時刻過期。②、設置key用不過期

  2. redis集群實現服務高可用:使用緩存服務器的集群模式,集群模式可以將數據分散存儲在多個節點上,當某個節點出現故障時,其他節點仍然可以正常提供服務,保證緩存服務的可用性。

  3. 多緩存結合:采用多級緩存架構,例如同時使用本地緩存(ehcache)+redis緩存。

  4. 服務降級:在應用層對請求進行限流,當請求量超過一定閾值時,直接拒絕部分請求,避免過多的請求直接訪問數據庫。


三、緩存穿透

(一)、名詞解釋

緩存穿透是指客戶端請求的數據在緩存中不存在,同時在數據庫中也不存在,這樣每次該請求都會穿透緩存,直接訪問數據庫。如果有大量這樣的無效請求持續涌入,會對數據庫造成極大的壓力,甚至可能導致數據庫不堪重負而崩潰。例如,黑客可能會故意發起大量不存在的鍵的請求,以消耗數據庫資源。


(二)、發生場景

  1. 黑客惡意攻擊:攻擊者可能會利用系統的漏洞,構造大量不存在的請求,如不存在的用戶 ID、商品 ID 等,向系統發起請求。由于這些請求對應的數據在緩存和數據庫中都不存在,會導致大量請求直接穿透緩存訪問數據庫,從而影響系統的正常運行。
  2. 業務數據異常:在業務系統中,可能會出現數據不一致或者數據刪除不及時的情況。
  3. 錯誤的用戶輸入:如果系統沒有對用戶輸入進行嚴格的驗證,用戶可能會輸入錯誤的查詢條件,如輸入一個不存在的訂單號、手機號碼等。這些無效請求會直接穿透緩存訪問數據庫。

(三)、預防與解決措施

1、方案一

緩存空值或默認值,當查詢的數據在數據庫中不存在時,在緩存中存儲一個空值或者默認值,并設置一個較短的過期時間。這樣下次相同的請求就可以直接從緩存中獲取空值或默認值,而不會再穿透到數據庫。


2、方案二

使用布隆過濾器,①、自研布隆過濾器。②、使用Google? Guava 庫實現布隆過濾器。


(四)、案例演示

自研簡略版布隆過濾器在上一篇已經學習過了,下面將學習Google Guava實現方式。Guava源碼地址:GitHub - google/guava: Google core libraries for Java

1、需求說明

模擬使用Guava布隆過濾器攔截掉非法數字,對于合法的數字放行。


2、導入依賴

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.2-jre</version>
</dependency>

3、編碼實現

public class GuavaBloomFilterDemo {public static void main(String[] args) {//誤判率,它越小誤判的個數也就越少(思考,是不是可以設置的無限小,沒有誤判豈不更好)//fpp the desired false positive probability 0.0 < fpp < 1.0,誤判率越低,消耗的資源越多,哈希函數也用的越多,誤判率也就越低// 默認值 0.03BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 1000000, 0.03);//1 先往布隆過濾器里面插入100萬的樣本數據for (int i = 1; i <= 1000000; i++) {bloomFilter.put(i);}List<Integer> list1 = Arrays.asList(120000000, 111111, 10, 222222222, 42575, 123457);list1.forEach(e -> {boolean result = bloomFilter.mightContain(e);if (result) {// TODO 查redis → 查數據庫 → .....System.out.println("存在,放行" + e);} else {// 直接返回結果System.out.println("不存在,攔截" + e);}});//故意取10萬個不在過濾器里的值,看看有多少個會被認為在過濾器里List<Integer> list = new ArrayList<>(1000000);for (int i = 1000000 + 1; i <= 1100000; i++) {if (bloomFilter.mightContain(i)) {list.add(i);}}System.out.println("誤判的總數量::{}" + list.size());}
}


四、緩存擊穿

(一)、名詞解釋

緩存擊穿是指在高并發的場景下,一個非常熱點的 key 在緩存中過期失效的瞬間,大量針對該 key 的請求同時涌入。由于此時緩存中沒有該 key 對應的數據,這些請求就會全部轉向數據庫去查詢。數據庫在短時間內需要處理大量的查詢請求,從而承受巨大的壓力,可能會導致數據庫性能急劇下降,甚至出現崩潰的情況,進而影響整個系統的正常運行。


(二)、發生場景

  1. 熱點數據過期:在電商系統中,一款熱門商品的信息會被大量用戶頻繁訪問,為了減輕數據庫壓力,會將該商品信息緩存起來并設置過期時間。當這個過期時間到達,緩存中的數據失效,而此時恰好有大量用戶同時發起對該商品信息的請求,就會出現緩存擊穿的情況。
  2. 流量突發:一些突發的熱點事件會導致瞬間產生大量的請求。比如,某明星突然發布一條微博,引發大量粉絲同時訪問其個人主頁,而該主頁信息在緩存中過期,大量請求就會直接沖向數據庫。
  3. 數據預熱不正確:比如新聞網站在每天早上進行緩存預熱,但遺漏了當天的一條重大熱點新聞,當用戶大量訪問該新聞時,就會出現問題。

(三)、預防與解決措施

1、方案一

使用雙檢加鎖策略。前面已經學習過了,不在闡述。

public String get(String key) {String value = redis.get(key);// 查詢緩存if (value != null) {//緩存存在直接返回return value;} else {//緩存不存在則對方法加鎖//假設請求量很大,緩存過期synchronized (this) {value = redis.get(key); // 在查一遍redisif (value == null) {// 從數據庫獲取數據value = dao.get(key);// 設置過期時間并回寫到緩存redis.setex(key, time, value);}return value;}}}

2、方案二

隨機退避策略。當發現緩存中熱點 key 失效時,讓各個請求不要立即去訪問數據庫,而是各自隨機等待一段不同的時間后再去嘗試獲取數據。這樣可以避免大量請求在同一時刻集中訪問數據庫,將請求的時間分散開,減輕數據庫在短時間內的壓力。

public String randomBackoffMethod(String key) {try {Jedis jedis = RedisUtils.getJedis();String data = jedis.get(key);if (data == null) {try {// 生成隨機退避時間 毫秒int backoffTime = new Random().nextInt(2000);Thread.sleep(backoffTime);// 再次嘗試從緩存獲取數據,// 但是在高并發場景下,可能線程隨機退避時間會一樣,// 為了避免造成緩存雙寫不一致問題,使用雙檢鎖策略來防止String value = jedis.get(key);// 查詢緩存if (value != null) {//緩存存在直接返回return value;} else {//緩存不存在則對方法加鎖//假設請求量很大,緩存過期synchronized (this) {value = jedis.get(key); // 在查一遍redisif (value == null) {// 從數據庫獲取數據value = dao.get(key);// 設置過期時間并回寫到緩存jedis.setex(key, time, value);}return value;}}} catch (InterruptedException e) {Thread.currentThread().interrupt();}}jedis.close();return data;} catch (Exception e) {e.printStackTrace();}return null;}

3、方案三

差異失效策略。它的核心思想是避免多個熱點 Key 在同一時刻同時失效,從而防止大量請求在瞬間全部涌向數據庫,給數據庫造成過大壓力。

在緩存擊穿場景中的實現方式為一個熱點key拷貝兩份,兩份緩存過期時間不一樣,將緩存失效的時間分散開來,以此保障系統的穩定性與性能。

/*** 差異失效策略查詢*/public String differentialFailureSelectMethod(String key) {// 同一個熱點key的前綴String prefixA = "keyA:";String prefixB = "keyB:";try {Jedis jedis = RedisUtils.getJedis();String data = jedis.get(prefixA + key);if (data == null) {System.out.println("=========A緩存已經失效");//用戶先查詢緩存A(上面的代碼),如果緩存A查詢不到(例如,更新緩存的時候刪除了),再查詢緩存Bdata = jedis.get(prefixB + key);if (data == null) {System.out.println("=========B緩存已經失效");//TODO 查數據庫 → 回寫redis}return data;}System.out.println("查詢結果:{}" + data);} catch (Exception ex) {ex.printStackTrace();}return null;}/*** 差異失效策略更新*/public void differentialFailureUpdateMethod(String key) {try {// 以前的某個熱點keyString oldHotKeyA = "oldHotKey:" + key;String oldHotKeyB = "oldHotKey:" + key;// 新熱點key前綴String prefixA = "newKeyA:";String prefixB = "newKeyB:";//模擬從數據庫查數據Jedis jedis = RedisUtils.getJedis();Object o = dao.get(key);//先更新B緩存jedis.del(oldHotKeyB);jedis.set(prefixB + o.getId());jedis.expire(prefixB + o.getId(), 2000);//再更新A緩存jedis.del(oldHotKeyA);jedis.set(prefixA + o.getId());jedis.expire(prefixA + o.getId(), 1000);} catch (Exception e) {e.printStackTrace();}}

五、總結?

一圖總結,四個問題以及解決辦法:

問題類型核心問題解決方案典型場景
緩存預熱數據未提前加載啟動加載、定時任務、腳本電商大促前的商品信息加載
緩存雪崩大量緩存失效隨機過期、集群、高可用、限流大量key過期、緩存服務器宕機時
緩存穿透無效請求攻擊布隆過濾器、緩存空值惡意攻擊場景
緩存擊穿熱點 Key 失效雙檢鎖、差異失效、隨機退避秒殺活動中的商品信息訪問

ps:努力到底,讓持續學習成為貫穿一生的堅守。學習筆記持續更新中。。。。

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

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

相關文章

Reflect.get和target[key]有何不同?

主要區別在this指向不同&#xff0c;下面輸出張三還是李四?&#xff1a; const person{name:張三,get FullName(){return this.name;},};let personProxynew Proxy(person,{get(target,key){return Reflect.get(target,key)//或者return target[key]}});const p1{__proto__:pe…

rust語言match模式匹配涉及轉移所有權Error Case

struct S{data:String, }//注意&#xff1a;因為String默認是移動語義&#xff0c;從而決定結構體S也是移動語義&#xff0c;可采用(1)或(2)兩種方法解決編譯錯誤&#xff1b;關鍵思路&#xff1a;放棄獲取結構體S的字段data的所有權&#xff0c;改為借用。fn process(s_ref:&a…

光譜相機檢測肉類新鮮度的原理

光譜相機通過分析肉類樣本在特定波長范圍內的光譜反射特性&#xff0c;結合化學與生物指標的變化規律&#xff0c;實現對其新鮮度的無損檢測。其核心原理可概括為以下方面&#xff1a; 一、光譜特征與物質成分的關聯性 ?物質特異性吸收/反射? 不同化學成分&#xff08;如水分…

c#面試題整理9

1.遍歷xml文檔 2.解釋一下這段 String s new String("xyz"); 這段在C#平臺中&#xff0c;編譯失敗 3.說明一下抽象類 抽象類可以有構造函數 抽象類不能是靜態和密封的類&#xff0c;密封的類表示無法繼承&#xff0c;抽象類本身就不可實例化&#xff0c;加不好…

《React 屬性與狀態江湖:從驗證到表單受控的實戰探險》

屬性初識 屬性能解決兩個大問題&#xff1a;通信和復用 props.js: import React, { Component } from react import Navbar from ./Navbarexport default class App extends Component {state {a:100}render() {return (<div><div><h2>首頁</h2>&l…

Qwen/QwQ-32B 基礎模型上構建agent實現ppt自動生成

關心Qwen/QwQ-32B 性能測試結果可以參考下 https://zhuanlan.zhihu.com/p/28600079208https://zhuanlan.zhihu.com/p/28600079208 官方宣傳上是該模型性能比肩滿血版 DeepSeek-R1&#xff08;671B&#xff09;&#xff01; 我們實現一個 使用Qwen/QwQ-32B 自動生成 PowerPoi…

Javascript基礎語法詳解

面向對象的語言.腳本語言,不需要編譯,瀏覽器解釋即可運行 .用于控制網頁的行為.瀏覽器的source可以打斷點調試, console輸入代碼可以執行 use strict指令: 在“嚴格模式”下運行js代碼, 防止意外創建全局變量等, 提高代碼安全性和執行效率. 使用: 全局嚴格模式&#xff1a;…

[雜學筆記] TCP和UDP的區別,對http接口解釋 , Cookie和Session的區別 ,http和https的區別 , 智能指針 ,斷點續傳

文章目錄 1. TCP和UDP的區別2. 對http接口解釋3. Cookie和Session的區別4. http和https的區別5. 智能指針6.斷點續傳 1. TCP和UDP的區別 tcp的特點&#xff1a; 面向連接&#xff0c;可靠性高&#xff0c;全雙工&#xff0c;面向字節流udp特點&#xff1a;無連接&#xff0c;不…

JAVASE(五)

目錄 一、成員變量和局部變量 1.定義 2.區別 &#xff08;1&#xff09;相同 &#xff08;2&#xff09;不同 二、方法和構造方法 1.定義 2.構造方法細節 3.方法重載 一、成員變量和局部變量 1.定義 &#xff08;1&#xff09;成員變量是…

Matlab中快速查找元素索引號

1、背景介紹 在算法設計過程中&#xff0c;有時候需要從一維/二維數組中&#xff0c;快速查找是否某個元素&#xff0c;以及該元素所在的位置。如一維矩陣[1 2 3 4 5 6 6 7 8]所示&#xff0c;元素6所在的位置為6 7。 2、函數測試 matlab中函數find()可以快速查找到指定元素所…

【DuodooTEKr 】多度科技 以開源之力,驅動企業數字化轉型

多度科技 背景 / Background 在全球產業鏈重構與國內經濟雙循環的浪潮下&#xff0c;中國制造業與貿易企業正面臨數字化升級的迫切需求。開源技術作為數字化轉型的基石&#xff0c;不僅能打破技術壁壘、降低企業成本&#xff0c;更能通過協作創新加速產業智能化進程。 多度科技…

【HarmonyOS Next】鴻蒙應用故障處理思路詳解

【HarmonyOS Next】鴻蒙應用崩潰處理思路詳解 一、崩潰問題發現后定位 1. 崩潰現象&#xff1a; 常見的崩潰問題表現為&#xff0c;應用操作后白屏閃退&#xff0c;或者應用顯示無響應卡死。 2.定位問題&#xff1a; 發現崩潰后&#xff0c;我們首先需要了解復現步驟&#x…

linunx ubuntu24.04.02裝libfuse2導致無法開機進不了桌面解決辦法

osu.appimage運行需要libfuse2 然后我就下了fuse,打了兩把第二天無法開機 這樣是不能開機的 這樣是可以開機的 解決辦法一&#xff1a;玩星火商店的osu&#xff0c;好了問題解決 解決辦法二&#xff1a; 在這個頁面 ctrl alt f2進入tty6 sudo apt install ubuntu-desktop 進…

Maven 的常用指令

一、核心構建指令 mvn clean 作用&#xff1a;刪除 target 目錄&#xff08;清理編譯/打包生成的文件&#xff09;。 場景&#xff1a;確保從頭開始構建&#xff0c;避免殘留文件干擾。 mvn compile 作用&#xff1a;編譯項目源代碼。 場景&#xff1a;快速檢查代碼是否能編…

llvm數據流分析

llvm數據流分析 1.數據流分析2.LLVM實現2.1.常量傳播2.2.活躍性分析 相關參考文檔&#xff1a;DataFlowAnalysisIntro、ustc編譯原理課程、南大程序分析課程1、南大程序分析課程2。 1.數據流分析 數據流分析在編譯優化等程序分析任務上都有重要應用。通常數據流分析可被抽象為…

C++ MySQL 常用接口(基于 MySQL Connector/C++)

C MySQL 常用接口&#xff08;基于 MySQL Connector/C&#xff09; 1. 數據庫連接 接口&#xff1a; sql::mysql::MySQL_Driver *driver; sql::Connection *con;作用&#xff1a; 用于創建 MySQL 連接對象。 示例&#xff1a; driver sql::mysql::get_mysql_driver_insta…

C++藍橋杯基礎篇(十一)

片頭 嗨~小伙伴們&#xff0c;大家好&#xff01;今天我們來學習C藍橋杯基礎篇&#xff08;十一&#xff09;&#xff0c;學習類&#xff0c;結構體&#xff0c;指針相關知識&#xff0c;準備好了嗎&#xff1f;咱們開始咯~ 一、類與結構體 類的定義&#xff1a;在C中&#x…

css中實現border距離視圖左右兩側有距離

首先看效果圖 再看css是如何實現 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.main {background-color: aqua;display: block;width: 300px;padding: 0px 32px;box-sizing: border-box;}/…

Ubuntu 22.04 無法進入圖形界面的解決方法

Ubuntu 22.04 無法進入圖形界面&#xff0c;只能進入 tty&#xff0c;可能是由于圖形界面相關的配置或驅動程序出現了問題。以下是一些常見的解決方法&#xff1a; 1. 檢查圖形界面服務狀態 首先&#xff0c;檢查圖形界面服務&#xff08;通常是 gdm 或 lightdm&#xff09;的…

Tweak Power:全方位電腦系統優化的高效工具

在日常使用電腦時&#xff0c;系統性能的下降、垃圾文件的堆積以及硬盤的老化等問題常常困擾著用戶。為了提升電腦性能、優化系統運行&#xff0c;許多人會選擇系統優化工具。然而&#xff0c;國內一些系統優化軟件常常因為廣告過多或功能冗雜而讓人望而卻步。此時&#xff0c;…