Spring Boot 項目中 Redis 常見問題及解決方案

目錄

  1. 緩存穿透
  2. 緩存雪崩
  3. 緩存擊穿
  4. Redis 連接池耗盡
  5. Redis 序列化問題
  6. 總結

1. 緩存穿透

問題描述

緩存穿透是指查詢一個不存在的數據,由于緩存中沒有該數據,請求會直接打到數據庫上,導致數據庫壓力過大。

解決方案

  1. 緩存空值:即使查詢的數據不存在,也將空值緩存起來,并設置一個較短的過期時間。
  2. 布隆過濾器:在查詢緩存之前,先通過布隆過濾器判斷數據是否存在。

示例代碼

@Service
public class UserService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public User getUserById(Long id) {String key = "user:" + id;// 從緩存中獲取數據User user = (User) redisTemplate.opsForValue().get(key);if (user != null) {return user;}// 緩存中不存在,查詢數據庫user = userRepository.findById(id).orElse(null);if (user == null) {// 緩存空值,設置較短的過期時間redisTemplate.opsForValue().set(key, null, 60, TimeUnit.SECONDS);} else {// 緩存查詢結果redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);}return user;}
}

2. 緩存雪崩

問題描述

緩存雪崩是指大量緩存數據在同一時間失效,導致所有請求都打到數據庫上,造成數據庫壓力過大甚至崩潰。

解決方案

  1. 設置不同的過期時間:為緩存數據設置隨機的過期時間,避免大量緩存同時失效。
  2. 使用分布式鎖:在緩存失效時,使用分布式鎖保證只有一個線程去加載數據。

示例代碼

@Service
public class ProductService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate RedissonClient redissonClient;public Product getProductById(Long id) {String key = "product:" + id;Product product = (Product) redisTemplate.opsForValue().get(key);if (product != null) {return product;}// 使用分布式鎖防止緩存擊穿RLock lock = redissonClient.getLock("lock:" + key);try {lock.lock();// 雙重檢查,防止其他線程已經加載了數據product = (Product) redisTemplate.opsForValue().get(key);if (product != null) {return product;}// 查詢數據庫product = productRepository.findById(id).orElse(null);if (product != null) {// 設置隨機的過期時間int expireTime = 3600 + new Random().nextInt(600); // 1小時 + 隨機10分鐘redisTemplate.opsForValue().set(key, product, expireTime, TimeUnit.SECONDS);}} finally {lock.unlock();}return product;}
}

3. 緩存擊穿

問題描述

緩存擊穿是指某個熱點數據在緩存中失效后,大量請求同時打到數據庫上,導致數據庫壓力過大。

解決方案

  1. 使用互斥鎖:在緩存失效時,使用互斥鎖保證只有一個線程去加載數據。
  2. 永不過期策略:對熱點數據設置永不過期,通過后臺任務定期更新緩存。

示例代碼

@Service
public class HotDataService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public String getHotData() {String key = "hot_data";String data = (String) redisTemplate.opsForValue().get(key);if (data != null) {return data;}// 使用 Redis 的 SETNX 實現互斥鎖String lockKey = "lock:" + key;boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);if (locked) {try {// 雙重檢查data = (String) redisTemplate.opsForValue().get(key);if (data != null) {return data;}// 模擬從數據庫加載熱點數據data = loadHotDataFromDB();redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);} finally {// 釋放鎖redisTemplate.delete(lockKey);}} else {// 未獲取到鎖,等待重試try {Thread.sleep(100);return getHotData(); // 重試} catch (InterruptedException e) {Thread.currentThread().interrupt();}}return data;}private String loadHotDataFromDB() {// 模擬數據庫查詢return "hot_data_from_db";}
}

4. Redis 連接池耗盡

問題描述

在高并發場景下,Redis 連接池可能會被耗盡,導致請求失敗。

解決方案

  1. 增加連接池大小:根據實際需求調整連接池的最大連接數。
  2. 優化連接使用:確保每次操作 Redis 后及時釋放連接。

示例代碼

application.yml 中配置連接池:

spring:redis:host: localhostport: 6379lettuce:pool:max-active: 50  # 最大連接數max-idle: 10   # 最大空閑連接數min-idle: 5    # 最小空閑連接數

5. Redis 序列化問題

問題描述

默認情況下,Spring Boot 使用 JdkSerializationRedisSerializer 進行序列化,可能導致存儲的數據不易閱讀或兼容性問題。

解決方案

使用更高效的序列化方式,如 Jackson2JsonRedisSerializerStringRedisSerializer

示例代碼

@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// 使用 Jackson2JsonRedisSerializer 序列化值Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);template.setValueSerializer(serializer);template.setHashValueSerializer(serializer);// 使用 StringRedisSerializer 序列化鍵template.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());return template;}
}

6. 總結

在 Spring Boot 項目中使用 Redis 時,可能會遇到緩存穿透、緩存雪崩、緩存擊穿、連接池耗盡以及序列化等問題。通過合理的緩存策略、分布式鎖、連接池配置和序列化方式,可以有效解決這些問題,提升系統的穩定性和性能。希望本文的解決方案和示例代碼能幫助到你!

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

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

相關文章

信息系統項目管理師--整合管理

信息系統項目管理師–整合管理

關于tomcat使用中瀏覽器打開index.jsp后中文顯示不正常是亂碼,但英文正常的問題

如果是jsp文件就在首行加 “<% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8" %>” 如果是html文件 在head標簽加入&#xff1a; <meta charset"UTF-8"> 以jsp為例子&#xff0c;我們…

微服務的春天:基于Spring Boot的架構設計與實踐

微服務的春天:基于Spring Boot的架構設計與實踐 在如今的技術領域,微服務架構儼然成為了解決復雜系統開發與運維挑戰的關鍵利器。作為一名資深運維和自媒體創作者,筆名Echo_Wish,我將深入探討基于Spring Boot的微服務架構設計,結合實例代碼說明觀點,希望能為大家帶來啟發…

JVM參數調整

一、內存相關參數 1. 堆內存控制 -Xmx&#xff1a;最大堆內存&#xff08;如 -Xmx4g&#xff0c;默認物理內存1/4&#xff09;。-Xms&#xff1a;初始堆內存&#xff08;建議與-Xmx相等&#xff0c;避免動態擴容帶來的性能波動&#xff09;。-Xmn&#xff1a;新生代大小&…

AVM 環視拼接 魚眼相機

https://zhuanlan.zhihu.com/p/651306620 AVM 環視拼接方法介紹 從內外參推導IPM變換方程及代碼實現&#xff08;生成AVM環視拼接圖&#xff09;_avm拼接-CSDN博客 經典文獻閱讀之--Extrinsic Self-calibration of the Surround-view System: A Weakly... (環視系統的外參自…

【哇! C++】類和對象(三) - 構造函數和析構函數

目錄 一、構造函數 1.1 構造函數的引入 1.2 構造函數的定義和語法 1.2.1 無參構造函數&#xff1a; 1.2.2 帶參構造函數 1.3 構造函數的特性 1.4 默認構造函數 二、析構函數 2.1 析構函數的概念 2.2 特性 如果一個類中什么成員都沒有&#xff0c;簡稱為空類。 空類中…

【五.LangChain技術與應用】【11.LangChain少樣本案例模板:小數據下的AI訓練】

深夜的創業孵化器里,你盯著屏幕上的醫療AI項目,手里攥著僅有的97條標注數據——這是某三甲醫院心內科攢了三年的罕見病例。投資人剛剛發來最后通牒:“下周demo要是還分不清心肌炎和感冒,就撤資!” 這時你需要掌握的不是更多數據,而是讓每個樣本都變成會復制的孫悟空的毫毛…

2005-2019年各省城鎮人口數據

2005-2019年各省城鎮人口數據 1、時間&#xff1a;2005-2019年 2、來源&#xff1a;國家統計局、統計年鑒 3、指標&#xff1a;地區、年份、城鎮人口(萬人) 4、范圍&#xff1a;31省 5、指標解釋&#xff1a;?城鎮人口是指居住在城市、集鎮的人口&#xff0c;主要依據人群…

Anaconda 部署 DeepSeek

可以通過 Anaconda 環境部署 DeepSeek 模型&#xff0c;但需結合 PyTorch 或 TensorFlow 等深度學習框架&#xff0c;并手動配置依賴項。 一、Anaconda 部署 DeepSeek 1. 創建并激活 Conda 環境 conda create -n deepseek python3.10 # 推薦 Python 3.8-3.10 conda activate…

Python 面向對象高級編程-定制類

目錄 __str__ __iter__ __getitem__ __getattr__ __call__ 小結 看到類似__slots__這種形如__xxx__的變量或者函數名就要注意&#xff0c;這些在Python中是有特殊用途的。 __slots__我們已經知道怎么用了&#xff0c;__len__()方法我們也知道是為了能讓class作用于len()…

MCP與RAG:增強大型語言模型的兩種路徑

引言 近年來&#xff0c;大型語言模型&#xff08;LLM&#xff09;在自然語言處理任務中展現了令人印象深刻的能力。然而&#xff0c;這些模型的局限性&#xff0c;如知識過時、生成幻覺&#xff08;hallucination&#xff09;等問題&#xff0c;促使研究人員開發了多種增強技…

IDEA Generate POJOs.groovy 踩坑小計 | 生成實體 |groovy報錯

一、無法生成注釋或生成的注釋是null 問題可能的原因&#xff1a; 1.沒有從表里提取注釋信息&#xff0c;修改def calcFields(table)方法即可 def calcFields(table) {DasUtil.getColumns(table).reduce([]) { fields, col ->def spec Case.LOWER.apply(col.getDataType().…

ue5.5崩潰報gpu錯誤快速修復注冊表命令方法

網上已經有很多方法了&#xff0c;自己寫了個regedit比處理dos批處理命令&#xff0c;啟動時需要win 管理員身份拷貝后&#xff0c;將以下代碼&#xff0c;保存為 run.bat格式批處理文件&#xff0c;右鍵鼠標&#xff0c;在彈出菜單中&#xff0c;選擇用管理員身份運行。即可。…

能量石[算法題]

題目來源&#xff1a;第十五屆藍橋杯大賽軟件賽省賽Java 大學 B 組&#xff08;算法題&#xff09; 可以參考一下&#xff0c;本人也是比較菜 不喜勿噴&#xff0c;求求求 import java.util.Scanner;?public class Main {public static void main(String[] args) {Scanner s…

馬爾科夫不等式和切比雪夫不等式

前言 本文隸屬于專欄《機器學習數學通關指南》&#xff0c;該專欄為筆者原創&#xff0c;引用請注明來源&#xff0c;不足和錯誤之處請在評論區幫忙指出&#xff0c;謝謝&#xff01; 本專欄目錄結構和參考文獻請見《機器學習數學通關指南》 正文 統計概率的利劍&#xff1a;掌…

基于 STC89C52 的 8x8 點陣顯示漢字

一、引言 在電子信息顯示領域,漢字的直觀呈現為信息傳遞帶來極大便利。8x8 點陣雖顯示空間有限,但通過合理設計,能夠清晰展示一些常用、簡單的漢字,豐富電子設備的交互界面。STC89C52 單片機作為一款經典且應用廣泛的微控制器,以其成本低廉、易于開發的特性,成為驅動 8x…

二進制、八進制、十進制和十六進制間的轉換(原理及工程實現)

在計算機科學和編程中&#xff0c;進制轉換是一個非常重要的基礎知識。無論是二進制、八進制、十進制還是十六進制&#xff0c;它們在不同的場景中都有廣泛的應用。本文將詳細介紹常用進制之間的轉換方法&#xff0c;并附上C語言示例代碼&#xff0c;幫助大家更好地理解和掌握這…

從零開始的 Kafka 學習(二)| 集群啟動

1. 相關概念 1.1 代理&#xff1a;Broker 使用Kafka前&#xff0c;我們都會啟動Kafka服務進程&#xff0c;這里的Kafka服務進程我們一般會稱之為Kafka Broker 或 Kafka Server。因為Kafka是分布式消息系統所以再實際的生產環境中&#xff0c;是需要多個服務進程形成集群提供消…

python如何隨機產生一堆數字并輸出

python隨機產生一堆數字并輸出的方法&#xff1a; 通過for循環語句多次執行for循環里面的“random.randint()”函數產生隨機數。將產生的隨機數賦值給變量&#xff0c;輸出這個變量就可以了 執行結果如下&#xff1a;

vue3與react、 react hooks

一、Vue3新特性&#xff1a;setup、ref、reactive、computed、watch、watchEffect函數、生命周期鉤子、自定義hooks函數、toRef和toRefs、shallowReactive 與 shallowRef、readonly 與 shallowReadonly、toRaw 與 markRaw、customRef、provide 與 inject、Fragment、Teleport、…