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.mzph.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、…