【Java面試】redis雪崩、穿透和擊穿詳解

一 Redis雪崩、穿透和擊穿

1. Redis雪崩
?Redis雪崩是指在某一時刻,緩存中大量的緩存數據同時失效或過期,導致大量的請求直接打到后端數據庫,導致數據庫負載劇增,引發性能問題甚至崩潰。這通常是因為緩存數據的過期時間設置過于集中,或者在同一時間段內大量緩存同時失效造成的。

2. Redis穿透
?Redis穿透是指惡意或者異常請求查詢一個不存在于緩存和數據庫中的數據,導致每次請求都會直接訪問數據庫,增加了數據庫負擔。這可能是攻擊者故意進行的,也可能是由于業務邏輯問題造成的。

3. Redis擊穿
?Redis擊穿是指某個熱點數據突然失效或被刪除,而此時大量請求正好同時訪問該熱點數據,導致這些請求都直接打到數據庫上,導致數據庫壓力激增。與雪崩不同,擊穿是因為某個特定的緩存數據失效導致。

示例:

讓我們以一個簡單的Java代碼示例來說明Redis雪崩、穿透和擊穿的概念。

假設有一個電影信息查詢系統,用戶可以根據電影ID查詢電影信息。我們使用Redis作為緩存來存儲電影信息,但是只對熱門電影設置了緩存,其他電影沒有被緩存。

@Service
public class MovieService {@Autowiredprivate MovieRepository movieRepository;@Autowiredprivate Jedis jedis;public Movie getMovieInfo(String movieId) {String cacheKey = "movie:" + movieId;String cachedInfo = jedis.get(cacheKey);if (cachedInfo == null) {Movie movie = movieRepository.findById(movieId);if (movie != null) {jedis.setex(cacheKey, 3600, movie.toString()); // 緩存1小時return movie;}}return Movie.fromString(cachedInfo);}
}

Redis雪崩示例:
假設在某一時刻,緩存中存儲了很多電影信息,這些緩存在同一時間內同時失效,導致大量請求直接訪問數據庫,造成數據庫壓力激增。

Redis穿透示例:
有一個惡意用戶不斷發送不存在的電影ID,每次請求都會繞過緩存,直接查詢數據庫,導致數據庫壓力增加。

Redis擊穿示例:
假設某個熱門電影的緩存在某個時間點失效,而在這個時間點正好有大量用戶同時查詢該電影信息,導致所有請求直接訪問數據庫,造成數據庫壓力激增。

二 解決方案


2.1 對緩存數據的過期時間進行隨機化,避免集中失效。

  1. 選擇隨機時間范圍: 首先,你需要選擇一個適當的隨機時間范圍,用于分散緩存數據的過期時間。例如,你可以選擇在原始過期時間基礎上添加一個隨機的秒數,這樣每個緩存項的過期時間就會稍微有所不同。

  2. 生成隨機時間: 在獲取緩存數據時,生成一個隨機的秒數,然后將其添加到原始過期時間上,得到一個新的過期時間。

  3. 設置緩存數據: 將緩存數據存儲到Redis中,并設置使用上一步生成的新過期時間。
    ?

    @Service
    public class CacheService {@Autowiredprivate Jedis jedis;public String getCachedData(String key) {String cachedData = jedis.get(key);if (cachedData == null) {// 查詢數據庫獲取數據String dbData = Database.queryData(key);if (dbData != null) {// 生成隨機的過期時間(在1小時基礎上隨機增加0-300秒)int originalExpireTime = 3600; // 1小時的秒數int randomSeconds = new Random().nextInt(300); // 0到300秒的隨機數int cacheDuration = originalExpireTime + randomSeconds;// 將數據存儲到緩存并設置隨機過期時間jedis.setex(key, cacheDuration, dbData);return dbData;}}return cachedData;}
    }
    

2.2 使用布隆過濾器來過濾惡意請求,防止緩存穿透。

使用布隆過濾器來過濾惡意請求,以防止緩存穿透是一種常見的防御策略。布隆過濾器是一種數據結構,用于判斷一個元素是否存在于集合中,它可以高效地進行快速查詢,但可能會有一定的誤判率。

下面是一個使用Spring Boot和布隆過濾器來防止緩存穿透的詳細舉例:

步驟:引入依賴: 在Spring Boot項目中,添加所需的依賴,包括Spring Boot、Jedis和Google Guava(用于實現布隆過濾器)。初始化布隆過濾器: 在啟動時初始化一個布隆過濾器,用于存儲已查詢的緩存鍵。查詢緩存數據: 在獲取數據之前,首先檢查布隆過濾器,如果緩存鍵可能存在,則再查詢緩存。import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import redis.clients.jedis.Jedis;@Service
public class CacheService {private final Jedis jedis;private final BloomFilter<String> bloomFilter;@Autowiredpublic CacheService(Jedis jedis) {this.jedis = jedis;this.bloomFilter = BloomFilter.create(Funnels.stringFunnel(), 1000, 0.01); // 初始化布隆過濾器}public String getCachedData(String key) {if (!bloomFilter.mightContain(key)) { // 判斷是否可能存在于集合中return null; // 不再查詢緩存和數據庫,直接返回null}String cachedData = jedis.get(key);if (cachedData == null) {// 查詢數據庫獲取數據String dbData = Database.queryData(key);if (dbData != null) {jedis.setex(key, 3600, dbData); // 緩存1小時bloomFilter.put(key); // 將鍵添加到布隆過濾器中return dbData;}}return cachedData;}
}

2.3 使用互斥鎖(例如分布式鎖)來防止擊穿,只允許一個請求去查詢數據庫,其他請求等待或直接使用緩存。

使用互斥鎖(分布式鎖)來防止擊穿是一種常見的策略,可以確保在緩存失效的情況下,只有一個請求能夠去查詢數據庫,其他請求需要等待該請求完成或直接使用緩存。下面是一個使用Spring Boot和Jedis實現分布式鎖來防止擊穿的代碼示例:

步驟:1、引入依賴: 在Spring Boot項目中,添加所需的依賴,包括Spring Boot和Jedis。2、獲取分布式鎖: 在查詢數據庫之前,使用分布式鎖來確保只有一個請求能夠進行數據庫查詢。3、釋放分布式鎖: 在查詢完成后,釋放分布式鎖,讓其他請求能夠繼續執行@Service
public class CacheService {@Autowiredprivate Jedis jedis;public String getCachedData(String key) {String cachedData = jedis.get(key);if (cachedData == null) {// 嘗試獲取分布式鎖,設置鎖的過期時間,防止死鎖String lockKey = "lock:" + key;String lockValue = "lockValue";SetParams params = new SetParams().ex(60).nx(); // 設置60秒過期時間,只有不存在時才設置String acquiredLock = jedis.set(lockKey, lockValue, params);if (acquiredLock != null) {try {// 查詢數據庫獲取數據String dbData = Database.queryData(key);if (dbData != null) {jedis.setex(key, 3600, dbData); // 緩存1小時return dbData;}} finally {// 釋放分布式鎖jedis.del(lockKey);}} else {// 等待一段時間后重新查詢緩存try {Thread.sleep(200); // 可以根據實際情況調整等待時間} catch (InterruptedException e) {Thread.currentThread().interrupt();}// 重新查詢緩存cachedData = jedis.get(key);}}return cachedData;}
}


2.4 合理設置緩存策略,確保熱門數據始終保持緩存,避免緩存雪崩。

確保熱門數據始終保持緩存,避免緩存雪崩,需要采取一些合理的緩存策略。以下是一些常見的合理方案:

1. 定時刷新緩存: 使用定時任務或調度器,定期刷新熱門數據的緩存。這可以確保緩存中的數據始終保持最新,避免數據過期。

2. 永不過期策略:對于熱門數據,可以設置永不過期的緩存策略。但要注意,如果熱門數據發生變化,需要手動更新緩存。

3. 熱點數據預加載:在應用啟動時,預先加載熱門數據到緩存中,確保緩存中存在最常用的數據。

4. 基于訪問頻率的過期策略:?根據數據的訪問頻率動態調整過期時間。訪問頻率高的數據設置較長的過期時間,訪問頻率低的數據設置較短的過期時間。

5. 分布式鎖控制:** 在緩存失效時,使用分布式鎖來防止多個請求同時查詢數據庫,確保只有一個請求進行查詢并更新緩存。

6. 降級策略:?如果緩存失效,可以暫時使用降級策略,例如返回默認值或靜態數據,以避免直接訪問數據庫。

7. 多級緩存:?使用多級緩存架構,將熱門數據存儲在多個緩存層中,例如內存緩存和分布式緩存,以提高數據的訪問速度和穩定性。

8. 請求合并:?對于同時涌入的大量請求,可以考慮將它們合并成一個請求,只查詢一次數據庫,然后將結果分發給多個請求。

9. 緩存預熱:?在系統負載較低的時候,提前將熱門數據加載到緩存中,以減少在高負載時的數據庫壓力。

10. 動態緩存策略:?根據系統的實際情況,動態調整緩存策略,例如根據時間段、節假日等因素來設置不同的緩存策略。

選擇合適的方案取決于你的業務需求和系統特點。通常,結合多個方案可以更好地保護熱門數據,避免緩存雪崩問題。

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

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

相關文章

機器學習筆記:李宏毅 stable diffusion

1 基本框架 ①&#xff1a;文字變成向量 ②&#xff1a;喂入噪聲文字encoder&#xff0c;產生中間產物 ③&#xff1a;decoder 還原圖片 2 text encoder 這張圖越往右下表示效果越好&#xff0c;可以看到text encoder尺寸越大&#xff0c;對后續生成圖片的增益越多 3 評價圖…

公園游玩必備!新零售模式如何吸引更多游客

隨著科技的不斷演進&#xff0c;新零售模式正以前所未有的速度改變著我們的購物方式和消費體驗。其中&#xff0c;自動售貨機作為新零售模式的重要組成部分&#xff0c;以其智能化、便捷性和多樣性的特點&#xff0c;正逐漸成為城市中熠熠生輝的一道風景線。 從24小時不間斷的運…

LeetCode Top100 Liked 題單(序號34~51)

?34. Find First and Last Position of Element in Sorted Array ? 題意&#xff1a;找到非遞減序列中目標的開頭和結尾 我的思路 用二分法把每一個數字都找到&#xff0c;最后返回首尾兩個數 代碼 Runtime12 ms Beats 33.23% Memory14 MB Beats 5.16% class Solution {…

前端練手小項目--自定義時間(html+css+js)

自定義時間 寫文章的因 關于要寫這篇文章的原因 是記錄在工作上遇到的困難需求&#xff0c;是希望能給大家提供一些解決問題的思路 接下來我描述這個需求的多樣性&#xff0c;難點在哪。 勾選勾選框開始時間與結束時間默認顯示昨天與今天。取消勾選框開始時間與結束時間清空。…

如何查看線程在哪個cpu核上

1、ps -eLF查看PSR值 2、 taskset -pc $pid&#xff08;進程/線程&#xff09; 參考鏈接&#xff1a;https://blog.csdn.net/test1280/article/details/87993669

Ubuntu修改設置系列--修改ssh端口號的方法(有示例)

原文網址&#xff1a;Ubuntu修改設置系列--修改ssh端口號的方法(有示例)_IT利刃出鞘的博客-CSDN博客 簡介 說明 本文介紹Ubuntu修改ssh端口號的方法(有示例)。 要達成的目標 ssh添加一個端口&#xff1a;3333&#xff0c;關閉原來的22端口。 1.修改端口 修改配置文件/et…

thingsboard編譯安裝踩坑記錄

thingsboard編譯安裝踩坑記錄 一、編譯&#xff1a;二、運行 朋友的thingsboard沒人維護&#xff0c;要裝新的服務器&#xff0c;啥文檔也沒有&#xff0c;就讓參考官網的文檔&#xff0c;版本也比較老3.2.2的&#xff0c;拿過來試了試記錄下踩坑的地方。 一、編譯&#xff1a;…

get與post如何拼接url與數據的靈活處理,循環的重要性。

get與post拼接url地址不同&#xff1a; let postData {method: "post",data: {op: "/api/setting/maintenanceperiod?period"this.authorizationCode,loadingConfig: {},data: {period:this.authorizationCode}}}; if(this.editData.id){let postData …

Nginx運行Vue項目:基本運行

需求 在Nginx服務器中&#xff0c;運行Vue項目。 說明 Vue項目打包生成的生產文件&#xff0c;是無法直接在瀏覽器打開的。需要放到Nginx服務器中&#xff0c;才能夠訪問。 本文章只介紹最基本的情況&#xff1a;Nginx中運行一個Vue項目。 實際生產環境&#xff0c;一個Ng…

mysql 批量給數據表和字段添加注釋

1、用命令行導出 mysql數據庫中的所有表 首先查看 mysql 的配置文件 “/etc/my.cnf ”&#xff0c;配置中找到 datadir 目錄&#xff0c; 將文件導出到 datadir 目錄下 我的 datadir 目錄是&#xff1a; /var/lib/mysql 連接mysql&#xff0c;執行導出命令 SELECT TABLE_NAM…

解密 AI 客服;在不同硬件設備上運行大型語言模型的可能性

&#x1f989; AI新聞 &#x1f680; 微軟必應首席執行官稱必應聊天優于OpenAI的GPT-4&#xff0c;但成本更高 摘要&#xff1a;微軟必應的首席執行官米哈伊爾?帕拉欣表示&#xff0c;必應聊天表現優于OpenAI的GPT-4&#xff0c;但使用了更高成本的檢索增強推理技術。必應聊…

中科億海微ROM使用

標題 ROM&#xff08;Read-Only Memory&#xff0c;只讀存儲器&#xff09;是一種在FPGA&#xff08;Field-Programmable Gate Array&#xff0c;現場可編程門陣列&#xff09;中常用的存儲器類型。與RAM&#xff08;Random Access Memory&#xff0c;機存取存儲器&#xff09;…

Nginx安全加固,版本隱藏及HTTP請求頭修改方法

1 隱藏nginx版本號 1.1 引言 nginx作為目前較為流行的http server軟件&#xff0c;其相關的安全漏洞也非常多&#xff0c;攻擊者可以根據我們的nginx版本來了解到相關的漏洞從而針對性的進行攻擊。 通過新版本的nginx都會修復一些老版本的已知漏洞&#xff0c;但有時候我們生…

二刷LeetCode--148. 排序鏈表(C++版本),必會題,思維題

思路&#xff0c;本題其實考察了兩個點&#xff1a;合并鏈表、鏈表切分。首先從1開始&#xff0c;將鏈表切成一段一段&#xff0c;因為需要使用歸并&#xff0c;所以下一次的切分長度應該是當前切分長度的二倍&#xff0c;每次切分&#xff0c;我們拿出兩段&#xff0c;然后將第…

虛擬機與Java虛擬機介紹

1、虛擬機 所謂虛擬機&#xff08;Virtual Machine&#xff09;&#xff0c;就是一臺虛擬的計算機。它是一款軟件&#xff0c;用來執行一系列虛擬計算機指令。大體上&#xff0c;虛擬機可以分為系統虛擬機和程序虛擬機。大名鼎鼎的Visual Box&#xff0c;VMware就屬于 系統虛…

提示丟失vcomp140.dll怎么辦?如何快速修復vcomp140.dll丟失問題

最近我遇到了一個程序啟動失敗的問題&#xff0c;錯誤提示顯示缺少了vcomp140.dll文件。經過一番研究和嘗試&#xff0c;我終于成功修復了這個問題。在這里&#xff0c;我將分享一下我的修復方法。 目錄 vcomp140.dll是什么&#xff1f; 如何快速修復呢&#xff1f; vcomp140…

sCrypt編程馬拉松于8月13日在復旦大學成功舉辦

繼6月在英國Exeter大學成功舉辦了為期一周的區塊鏈編程馬拉松后&#xff0c;美國sCrypt公司創始人兼CEO劉曉暉博士帶領核心團隊成員王一強、鄭宏鋒、周全&#xff0c;于8月13日在復旦大學再次成功舉辦了一場全新的sCrypt編程馬拉松。 本次活動由上海可一澈科技有限公司與復旦大…

C++筆記之花括號和圓括號初始化區別,列表初始化和初始化列表區別

C筆記之花括號和圓括號初始化區別&#xff0c;列表初始化和初始化列表區別 code review! 文章目錄 C筆記之花括號和圓括號初始化區別&#xff0c;列表初始化和初始化列表區別1.花括號{}進行初始化和圓括號()進行初始化2.列表初始化&#xff08;list initialization&#xff0…

Vitis高層次綜合學習——FPGA

高層次綜合 什么是高層次綜合&#xff1f;就是使用高級語言&#xff08;如C/C&#xff09;來編寫FPGA算法程序。 在高層次綜合上并不需要制定微架構決策&#xff0c;如創建狀態機、數據路徑、寄存器流水線等。這些細節可以留給 HLS 工具&#xff0c;通過提供輸入約束&#xff…

專訪阿里云席明賢,視頻云如何運用大模型與小模型來破繭升級2.0

不久前&#xff0c;LiveVideoStack與阿里云視頻云負責人席明賢&#xff08;花名右賢&#xff09;展開一場深度的對話&#xff0c;一個是圈內專業的社區媒體&#xff0c;一個是20年的IT老兵&#xff0c;雙方有交集、有碰撞、有火花。 面對風云變幻的內外環境&#xff0c;阿里云…