news 2026/6/9 17:39:22

Redis缓存三大问题详解:击穿、穿透与雪崩的解决方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis缓存三大问题详解:击穿、穿透与雪崩的解决方案

在使用 Redis 作为缓存层时,我们经常会遇到三个经典问题:缓存击穿、缓存穿透和缓存雪崩。这些问题可能导致系统性能下降甚至崩溃,本文将详细介绍这三个问题的原因和解决方案。

一、🎯 缓存击穿

问题描述:某个热点 key 在缓存中过期的瞬间,大量请求同时访问数据库,造成数据库压力骤增。
解决方案:

1.1 设置热点永不过期

案例代码:

// 对于热点数据,可以不设置过期时间 redisTemplate.opsForValue().set("hot_data", data);

1.2 互斥锁机制

使用互斥锁防止多个线程同时访问数据库。

案例代码:

public String getDataWithMutex(String key) { String value = redisTemplate.opsForValue().get(key); if (value == null) { // 获取分布式锁 Boolean lock = redisTemplate.opsForValue() .setIfAbsent("lock:" + key, "1", Duration.ofSeconds(10)); if (lock) { try { // 查询数据库 value = queryFromDatabase(key); // 写入缓存 redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(5)); } finally { // 释放锁 redisTemplate.delete("lock:" + key); } } else { // 等待其他线程加载完成 Thread.sleep(100); return getDataWithMutex(key); } } return value; }

1.3 接口限流与熔断

重要接口设置限流策略,防止恶意刷接口,同时进行熔断处理

二、🔍 缓存穿透

问题描述:查询一个不存在的数据,缓存和数据库都查不到,每次请求都会打到数据库,浪费系统资源。

解决方案:

2.1 接口层增加校验

如用户鉴权校验,id做基础校验,id<=0的直接拦截

2.2 缓存空值

对于缓存和数据库中都没有的数据,将key-value对写为key-null,设置短期有效时间

代码如下:

public String getDataWithNullCache(String key) { String value = redisTemplate.opsForValue().get(key); if (value == null) { // 查询数据库 value = queryFromDatabase(key); if (value == null) { // 缓存空值,设置较短过期时间 redisTemplate.opsForValue().set(key, "", Duration.ofMinutes(1)); return null; } else { // 缓存真实数据 redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(10)); } } else if (value.isEmpty()) { // 缓存的空值 return null; } return value; }

2.3 布隆过滤器

使用布隆过滤器快速判断数据是否存在于缓存中,避免频繁访问数据库。

什么是布隆过滤器?

------------布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。以Redis中的布隆过滤器实现为例,Redis中的布隆过滤器底层是一个大型位数组(二进制数组)+多个无偏hash函数。在布隆过滤器增加元素之前,首先需要初始化布隆过滤器的空间,也就是上面说的二进制数组,除此之外还需要计算无偏hash函数的个数。隆过滤器提供了两个参数,分别是预计加入元素的大小n,运行的错误率f。布隆过滤器中有算法根据这两个参数会计算出二进制数组的大小l,以及无偏hash函数的个数k。布隆过滤器支持增加和查询,不支持删除和修改。 关系就是:错误率越低,位数组越长,控件占用较大;错误率越低,无偏hash函数越多,计算耗时较长

案例代码:

@Component public class BloomFilterService { private final RedisTemplate<String, Object> redisTemplate; // 添加数据到布隆过滤器 public void addToBloomFilter(String key) { redisTemplate.opsForValue().setBit("bloom:user", hash(key), true); } // 检查数据是否存在 public boolean mightContain(String key) { long hash1 = hash(key); long hash2 = hash2(key); for (int i = 0; i < 3; i++) { long combinedHash = hash1 + i * hash2; if (!redisTemplate.opsForValue().getBit("bloom:user", combinedHash)) { return false; } } return true; } private long hash(String key) { return key.hashCode() & Integer.MAX_VALUE; } private long hash2(String key) { return (key.hashCode() >> 16) & Integer.MAX_VALUE; } }

布隆过滤器的其他典型应用

  • 网页URL去重:爬虫系统中判断网页是否已抓取
  • 垃圾邮件过滤:判断邮件地址是否为垃圾邮件发送者
  • 数据库查询优化:避免查询不存在的数据记录
  • 推荐系统:过滤用户已看过的内容

三、❄️ 缓存雪崩

问题描述:大量缓存 key 在同一时间过期,导致大量请求直接打到数据库,造成数据库瞬时压力过大。

解决方案:

3.1 过期时间随机化

避免大量数据同时过期

public void setCacheWithRandomExpire(String key, Object value) { // 基础过期时间 + 随机时间 int baseExpire = 300; // 5分钟 int randomExpire = new Random().nextInt(600); // 0-10分钟随机 redisTemplate.opsForValue().set( key, value, Duration.ofSeconds(baseExpire + randomExpire) ); }

3.2 构建高可靠集群

通过主从节点方式构建Redis缓存高可靠集群,避免单点故障。

3.3 服务降级与限流

在缓存雪崩发生时,启动请求限流机制,减少数据库压力

@Component public class CacheProtectionAspect { private final RateLimiter rateLimiter = RateLimiter.create(1000); // 限流1000QPS @Around("@annotation(com.example.annotation.CacheProtected)") public Object protectCacheAccess(ProceedingJoinPoint joinPoint) throws Throwable { if (!rateLimiter.tryAcquire()) { // 限流触发,返回默认值或抛出异常 throw new RuntimeException("系统繁忙,请稍后重试"); } try { return joinPoint.proceed(); } catch (Exception e) { // 降级处理 return getDefaultFallbackValue(); } } private Object getDefaultFallbackValue() { // 返回默认值或从备用数据源获取 return "default_value"; } }

总结缓存击穿、穿透和雪崩的区别可从下图看出:

redis缓存击穿、穿透、雪崩的了解就到这里了,这部分内容在软考中也可能会被考到。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 10:41:47

图片转文字技术(一)从光学识别到智能理解的演进之路

引言 在数字化浪潮中&#xff0c;图片转文字技术已悄然渗透到我们日常生活的方方面面。从手机相册中提取证件信息&#xff0c;到扫描纸质文档生成可编辑文本&#xff1b;从自动驾驶汽车识别路牌&#xff0c;到视障人士通过屏幕阅读器获取图像内容——这项技术的应用场景正在不断…

作者头像 李华
网站建设 2026/6/10 13:29:45

【Python与生活】Python实战 | 全网最全QS世界大学排名分析

一、前言 QS世界大学排名是全球最具影响力的大学排名之一&#xff0c;无论是留学选校、学术研究还是高校竞争力分析&#xff0c;都有重要参考价值。本文将手把手教你用Python完成QS排名的数据爬取、清洗、分析与可视化&#xff0c;从0到1实现完整的数据分析流程&#xff0c;即使…

作者头像 李华
网站建设 2026/6/10 15:22:30

在C# 中搭建基于VisionPro的多相机多线程采集与Socket通讯的视觉系统

c#visionpro视觉系统源代码 多相机多线程采集 Socket通讯在工业自动化和机器视觉领域&#xff0c;多相机多线程采集数据并通过Socket通讯进行数据传输是一项常见且重要的任务。借助C# 的强大功能以及VisionPro视觉系统&#xff0c;我们可以高效地实现这一过程。 多相机多线程采…

作者头像 李华
网站建设 2026/6/10 15:32:17

服务架构相关知识及演进

1. 基本概念应用&#xff08;Application&#xff09;/ 系统&#xff08;system&#xff09; 完成一整套服务的一个程序或一组相互配合的程序群模块&#xff08;Module&#xff09;/ 组件&#xff08;Component&#xff09; 应用程序复杂时&#xff0c;会将其划分不同的部分&am…

作者头像 李华
网站建设 2026/6/10 14:38:52

Ascend C 与 CUDA 的对比分析-为异构计算开发者提供迁移指南

目录 &#x1f3af; 摘要 1. 架构哲学&#xff1a;两种不同的AI计算世界观 1.1 &#x1f504; 从"通用加速"到"AI原生"的范式转移 1.2 &#x1f3d7;️ 硬件架构的本质差异 2. 编程模型对比&#xff1a;从线程到任务块的范式革命 2.1 ⚙️ CUDA的线程…

作者头像 李华
网站建设 2026/6/10 14:34:47

PPO是属于什么类型的RL算法,on policy还是off policy

PPO是属于什么类型的RL算法&#xff0c;on policy还是off policyPPO&#xff08;Proximal Policy Optimization&#xff09;属于 on-policy 的强化学习算法。结论一句话&#x1f449; PPO 是 on-policy 的策略梯度&#xff08;Policy Gradient&#xff09;方法&#xff0c;而不…

作者头像 李华