当前位置: 首页 > news >正文

Redis:缓存雪崩、穿透、击穿的技术解析和实战方案

🚨 1、简述

随着系统规模扩大,Redis 缓存被广泛用于数据预热、热点数据防护和高并发系统优化。然而在高并发环境中,缓存雪崩、穿透、击穿等问题若处理不当,可能导致系统雪崩式崩溃。

本文从原理、原因出发,结合实际项目经验,讲解如何应对这三大常见问题,并给出对应实践方案。

在这里插入图片描述


💣 2、缓存雪崩(Cache Avalanche)

✅ 定义:

大量缓存同时失效,导致请求直接打到数据库或下游服务,造成系统瞬时过载甚至崩溃。

🧨 触发场景:

🔹 同一时间大量缓存设置了相同过期时间。
🔹 Redis 故障、重启或崩溃,导致全缓存失效。

✅ 解决方案:

方案实现方式
缓存过期时间加随机给不同缓存设置随机 TTL(如 ±5%)
本地限流/降级Hystrix、Sentinel、RateLimiter 等
缓存预热应用启动时加载关键缓存数据
多级缓存引入本地缓存(如 Caffeine)减少对 Redis 的依赖
异步重建缓存通过队列异步刷新热点数据缓存

🛠 实践样例:设置随机过期时间

int baseExpire = 60 * 10; // 10分钟
int random = new Random().nextInt(60); // 加1分钟以内的随机值
redisTemplate.opsForValue().set("product:123", data, baseExpire + random, TimeUnit.SECONDS);

🕳️ 3、缓存穿透(Cache Penetration)

✅ 定义:

请求的数据既不在缓存中,也不在数据库中,攻击者通过大量随机 key 造成数据库压力激增。

🧨 触发场景:

🔹 攻击者构造不存在的 key 请求接口。
🔹 key 本身无意义(如 user:-1)

✅ 解决方案:

方案实现方式
缓存空对象查询结果为 null,也缓存一段时间(短 TTL)
参数校验请求层校验 ID 合法性,如 ID > 0
布隆过滤器使用布隆过滤器拦截不存在的 key 请求
接口限流控制访问频率,防止恶意请求刷爆系统

🛠 实践样例:缓存空值

String key = "user:1000";
String userJson = redisTemplate.opsForValue().get(key);if (userJson == null) {User user = userService.getById(1000L);if (user == null) {// 缓存一个占位符,防止穿透redisTemplate.opsForValue().set(key, "", 5, TimeUnit.MINUTES);} else {redisTemplate.opsForValue().set(key, toJson(user), 10, TimeUnit.MINUTES);}
}

🛠 实践样例:布隆过滤器(Guava)

BloomFilter<Long> filter = BloomFilter.create(Funnels.longFunnel(), 100_0000);
filter.put(12345L);if (!filter.mightContain(requestedId)) {return null; // 拦截非合法请求
}

🔥 4、缓存击穿(Cache Breakdown)

✅ 定义:

某个热点 key 失效瞬间,多个并发请求同时击中数据库。

🧨 触发场景:

🔹 热点数据过期,瞬时大量请求访问该 key。
🔹 并发场景下没有做好互斥更新控制。

✅ 解决方案:

方案实现方式
热点缓存永不过期主动更新替代被动过期
加互斥锁只有一个线程能加载数据,其余等待或返回旧值
异步更新缓存提前设置过期,后台刷新
多级缓存本地缓存兜底,如 Caffeine + Redis

🛠 实践样例:互斥锁方式防止击穿

public User getUserById(Long userId) {String key = "user:" + userId;String cache = redisTemplate.opsForValue().get(key);if (cache != null) return parseUser(cache);// 加锁防击穿String lockKey = "lock:user:" + userId;boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);if (!lock) {try { Thread.sleep(50); } catch (InterruptedException ignored) {}return getUserById(userId); // 递归重试}try {User user = db.queryById(userId);if (user != null) {redisTemplate.opsForValue().set(key, toJson(user), 10, TimeUnit.MINUTES);} else {redisTemplate.opsForValue().set(key, "", 3, TimeUnit.MINUTES);}return user;} finally {redisTemplate.delete(lockKey); // 释放锁}
}

🎯 5、总结

🔹 Redis 作为缓存层时,不应将其设计为单点依赖
🔹 搭配使用 Caffeine(本地)+ Redis(远程)+ MQ异步回源 是中大型系统推荐策略。
🔹 限流、熔断、降级 机制应作为系统稳定性的基本保障。

问题定义触发条件核心解决策略
雪崩批量缓存同时失效TTL 设置一致或 Redis 崩溃随机 TTL、本地缓存、限流
穿透请求的 key 无效缓存和数据库都无数据空值缓存、布隆过滤器、参数校验
击穿某一热点 key 失效突然大流量请求互斥锁、异步更新、热点永不过期
http://www.lryc.cn/news/604508.html

相关文章:

  • 矩阵指数函数 e^A
  • 如何利用 Redis 的原子操作(INCR, DECR)实现分布式计数器?
  • 微算法科技MLGO突破性的监督量子分类器:纠缠辅助训练算法为量子机器学习开辟新天地
  • 代码随想录算法训练营第五十五天|图论part5
  • Python设计模式详解:策略模式(Strategy Pattern)实战指南
  • OpenBayes 教程上新丨仅激活 3B 参数可媲美 GPT-4o,Qwen3 深夜更新,一手实测来了!
  • 代码随想录day50图论1
  • Apache Ignite 与 Spring Boot 集成
  • 学习游戏制作记录(冻结敌人时间与黑洞技能)7.30
  • nginx安装配置Lua模块的支持
  • 我的世界模组开发教程——资源(1)
  • 【AI】入门级提示词模板:适用于ChatGPT、文心一言等主流模型
  • 【ee类保研面试】数学类---线性代数
  • 从0开始学习R语言--Day62--RE插补
  • JVM对象创建与内存分配机制深度剖析
  • 基于Catboost的铁路交通数据分析及列车延误预测系统的设计与实现【全国城市可选、欠采样技术】
  • 【JVM篇11】:分代回收与GC回收范围的分类详解
  • 数据分析师进阶——95页零售相关数据分析【附全文阅读】
  • JVM 性能调优实战:让系统性能 “飞” 起来的核心策略
  • 观远 ChatBI 完成 DeepSeek-R1 大模型适配:开启智能数据分析跃升新篇
  • 【Spring】一文了解SpringMVC的核心功能及工作流程,以及核心组件及注解
  • Linux 日志管理与时钟同步详解
  • GIS工程师面试题
  • GitHub 热门项目 PandaWiki:零门槛搭建智能漏洞库,支持 10 + 大模型接入
  • UG NX二次开发(Python)-根据封闭曲线创建拉伸特征
  • Class27GoogLeNet
  • 实用性方案:高效处理图片拼接的正确打开方式
  • sed编程入门
  • [Agent开发平台] Coze Loop开源 | 前端 | typescript架构API速查
  • Python Pandas.get_dummies函数解析与实战教程