Redis 三大缓存问题:缓存穿透、缓存击穿、缓存雪崩原理 + 解决方案
前言在高并发项目里我们通常使用「Redis 缓存 MySQL 数据库」架构优先查询 Redis命中直接返回缓存未命中查询数据库再把结果写入缓存减轻数据库压力。 但是这个架构存在三类经典问题缓存穿透、缓存击穿、缓存雪崩。三者都会造成大量请求打到数据库严重时数据库 CPU 打满服务宕机。区分穿透查询不存在的数据缓存和数据库都没有请求直达 DB击穿热点 key 过期大量并发请求同时打到同一条数据直击 DB雪崩大量 key 同一时间过期大量请求同时涌入数据库一、缓存穿透Cache Penetration1. 定义查询数据库根本不存在的数据Redis 缓存里自然也没有这个 key。请求绕过缓存直接访问 MySQL。 如果有人恶意攻击批量传入不存在的 ID会持续压垮数据库。场景举例前端传userId-1、商品 id99999999数据库无此商品。 查询流程Redis 查不到 → 查询 MySQL返回空 → 不会把空结果写入缓存 → 下一次相同请求依旧再次查库。2. 解决方案方案 1缓存空值最简单中小项目首选查询数据库不存在时往 Redis 写入空值设置较短过期时间例如 2 分钟。 后续相同请求直接命中 Redis 空结果不再访问数据库。//伪代码 public Goods getGoodsById(Long id){ String key goods: id; String cacheVal redisTemplate.opsForValue().get(key); if(cacheVal ! null){ if(.equals(cacheVal)){ return null; // 缓存空对象代表数据不存在 } return JSON.parseObject(cacheVal, Goods.class); } //缓存未命中查询数据库 Goods goods goodsMapper.selectById(id); if(goods null){ // 数据库不存在存入空值过期2分钟 redisTemplate.opsForValue().set(key, , 2, TimeUnit.MINUTES); return null; } redisTemplate.opsForValue().set(key, JSON.toJSONString(goods), 30, TimeUnit.MINUTES); return goods; }优点实现简单缺点如果恶意传入大量不同不存在 idRedis 会存入大量无用空 key占用内存。方案 2布隆过滤器BloomFilter高并发、防恶意攻击推荐提前把数据库所有有效 id加载进布隆过滤器。请求进来先过布隆过滤器布隆过滤器判定不存在 → 直接返回不查 Redis、不查 DB布隆过滤器判定存在 → 继续查询 Redis、数据库布隆过滤器特点存在误判不会漏判。说不存在一定不存在说存在有可能不存在。优点内存占用极小适合海量数据抵御恶意攻击缺点有一定误判率新增数据需要同步维护布隆过滤器删除困难。方案 3接口层参数校验在接口最外层做参数校验ID 不能负数、ID 长度校验非法参数直接拦截。作为辅助方案不能单独解决穿透。二、缓存击穿Cache Breakdown1. 定义某个热点 Key超高访问量在 Redis 中过期。大量并发请求同时进来缓存失效全部打到数据库。重点只有一个热点 key 失效不是大批量 key。秒杀爆款商品、首页热门数据就是典型热点 key。场景秒杀商品 keyQPS 几千刚好 key 过期一瞬间上千请求同时绕过缓存访问 MySQL。2. 解决方案方案 1互斥锁分布式锁缓存失效时只放行一个请求去查数据库并更新缓存其余请求等待重试。 一般使用 Redisson 分布式锁。 伪代码public Goods getHotGoods(Long id){ String key goods: id; String val redisTemplate.opsForValue().get(key); if(val ! null){ return JSON.parseObject(val, Goods.class); } // 缓存失效尝试获取分布式锁 String lockKey lock:goods: id; boolean lock redissonClient.getLock(lockKey).tryLock(5,30,TimeUnit.SECONDS); if(lock){ try{ //拿到锁再次检查缓存防止等待期间别的线程已经更新 String val2 redisTemplate.opsForValue().get(key); if(val2 ! null){ return JSON.parseObject(val2, Goods.class); } Goods goods goodsMapper.selectById(id); redisTemplate.opsForValue().set(key, JSON.toJSONString(goods),30,TimeUnit.MINUTES); return goods; }finally { redissonClient.getLock(lockKey).unlock(); } }else{ //没拿到锁短暂休眠后重试 Thread.sleep(50); return getHotGoods(id); } }优点保证数据库不会被并发打穿数据一致性强缺点会有等待接口响应变慢存在死锁风险需要设置锁超时。方案 2热点 key 永不过期生产热点数据最推荐不设置过期时间。后台开启异步线程定时主动更新缓存而不是依靠过期被动触发更新。本质从根源上杜绝 key 过期自然不会击穿。优点没有锁等待性能最好无击穿风险缺点代码复杂度提升存在缓存和数据库短暂不一致窗口。面试区分互斥锁是按需更新永不过期 后台定时主动刷新适合超高 QPS 热点。三、缓存雪崩Cache Avalanche1. 定义大量缓存 key 在同一时间段集体过期大量请求同时无法命中缓存海量流量直接冲击数据库数据库压力瞬间飙升引发服务雪崩甚至级联宕机。和击穿区别击穿是单个热点 key 过期雪崩是大批量 key 同时过期。 另外一种雪崩场景Redis 服务宕机集群断电、主从切换故障所有缓存全部不可用流量全部打 DB。2. 解决方案方案 1过期时间加随机值【最简单优先使用】给 key 设置过期时间时增加随机偏移量避免大量 key 过期时间集中。 例如原本 30 分钟过期改为30分钟 随机1~5分钟。// 原30分钟 // redisTemplate.set(key,value,30,TimeUnit.MINUTES); // 修改后打散过期时间 int random new Random().nextInt(5); redisTemplate.opsForValue().set(key, JSON.toJSONString(goods),30random, TimeUnit.MINUTES);优点一行代码改造低成本解决大批量 key 同时过期问题缺点只能解决「key 同时过期」无法解决 Redis 宕机引发的雪崩。方案 2Redis 集群高可用主从 哨兵 / Redis Cluster部署集群主节点宕机自动故障转移避免单点 Redis 挂掉整体缓存不可用。解决 Redis 实例宕机场景。方案 3多级缓存本地 Caffeine RedisJVM 本地缓存Caffeine作为一级缓存Redis 二级缓存。即使 Redis 全部失效本地缓存还能扛住一部分流量作为兜底。优点双重保护抗风险强缺点本地缓存多实例数据一致性维护成本高。方案 4限流 熔断降级兜底防护使用 Sentinel/Guava 限流。当数据库压力过高触发熔断直接返回兜底数据拒绝新请求。属于最后一道防线防止数据库被打死。四、三大问题对比总结表问题核心原因场景核心方案缓存穿透查询不存在的数据缓存 DB 都没有恶意攻击、非法 ID缓存空值、布隆过滤器、参数校验缓存击穿单个热点 key 过期并发打 DB秒杀爆款分布式互斥锁、热点 key 永不过期异步刷新缓存雪崩大量 key 同时过期 / Redis 宕机批量数据过期Redis 故障过期加随机值、Redis 集群、多级缓存、限流熔断五、生产环境选型建议普通业务缓存空值 过期时间加随机值低成本解决穿透 雪崩热点数据使用永不过期 异步刷新避免击穿。对外高并发、防攻击系统布隆过滤器拦截穿透。核心链路增加 Sentinel 限流熔断兜底Redis 集群保证高可用。不推荐大量业务使用分布式锁锁会降低接口吞吐只在热点 key 场景使用。六、面试合集Q1缓存击穿和雪崩的区别A击穿是单个热点 key 过期雪崩是大量 key 同时失效或者 Redis 整体不可用。Q2布隆过滤器有什么缺点A存在误判无法删除元素新增数据需要同步维护。Q3热点 key 永不过期如何保证缓存和数据库一致性A数据库更新时主动更新 Redis 缓存后台定时任务兜底刷新允许短暂最终一致性。Q4缓存雪崩除了 key 同时过期还有什么场景怎么处理ARedis 集群宕机。解决方案Redis 哨兵 / 集群高可用、多级缓存、限流熔断降级。结语缓存穿透、击穿、雪崩是缓存架构最基础也是最重要的问题。面试很多人只会背概念分不清场景讲不出方案优缺点。实际开发中优先低成本方案不要过度设计高并发核心链路多层防护。理解这三个问题是设计高可用缓存架构的基础。

相关新闻

手搓 OpenClaw 自动启动神器:systemd 与脚本守护完整实践

手搓 OpenClaw 自动启动神器:systemd 与脚本守护完整实践

我是在一次服务器重启之后才下定决心手搓这个 OpenClaw 自动启动神器的。当时的情况特别尴尬:OpenClaw 服务依赖的环境变量、配置文件路径、还有那几个必须按顺序启动的依赖进程,全凭脑子记。凌晨两点爬起来敲命令行,敲到第三步发现忘了之前改…

2026/10/19 4:02:29 阅读更多 →
DeskcommCRM实施复盘:从工单到商机的客户全生命周期管理

DeskcommCRM实施复盘:从工单到商机的客户全生命周期管理

先交代一下背景。团队从五个人涨到四十几个人的时候,日常客户信息的流转开始失控了。微信群里的客户需求、售后群里的截图、销售各自维护的Excel、客服只读不回的工单表——这些东西各管各的,一旦客户追问进度,几乎所有人都要花五分钟去回忆“…

2026/10/19 4:01:28 阅读更多 →
open-code-review:开源工具链驱动的自动化代码审查实战方案

open-code-review:开源工具链驱动的自动化代码审查实战方案

做Code Review这件事,说实话挺反人性的。写完代码那一刻,大脑就自动进入了"我的代码没问题"的状态,再让你回头逐行挑自己的毛病,效率低不说,还经常漏掉真正要命的问题。我前后在几个团队里折腾过不同的Code …

2026/10/19 4:01:28 阅读更多 →

最新新闻

HTTP头四重校验与X-Forwarded-For绕过实战

HTTP头四重校验与X-Forwarded-For绕过实战

1. 这不是一道“密码题”,而是一次Web安全思维的现场复盘“BUUCTF[ZJCTF 2019]NiZhuanSiWei”——光看标题,很多人第一反应是:“哦,又一个CTF密码题,估计要转进制、换编码、套凯撒……”但真正动手做过这道题的人会发现…

2026/10/19 5:35:24 阅读更多 →
大模型API蜜罐实战:从诱饵设计到攻击捕获全解析

大模型API蜜罐实战:从诱饵设计到攻击捕获全解析

1. 大模型API的蜜罐,为什么和传统蜜罐不是一回事蜜罐这个词,安全圈的朋友都不陌生。一个故意暴露的脆弱服务,一个记录了所有试探动作的陷阱,等攻击者踩进来之后,我们再慢慢拆解他的手法、工具链和真实意图。传统场景里…

2026/10/19 5:35:24 阅读更多 →
C# WebAPI 连接 SQL Server 实战:从 Demo 到生产避坑指南

C# WebAPI 连接 SQL Server 实战:从 Demo 到生产避坑指南

简介:这份 C# WebAPI 示例代码面向具备一定 .NET 基础的开发者,用于快速理解基于 ASP.NET 构建 RESTful 风格 HTTP 服务的完整流程,并演示如何与 SQL Server 数据库进行数据交互。示例涵盖 ApiController 控制器编写、HttpGet/HttpPost 等 HT…

2026/10/19 5:35:24 阅读更多 →
自动化测试AI接入前必须解决的上下文对齐问题

自动化测试AI接入前必须解决的上下文对齐问题

1. 这不是加个API调用那么简单:为什么AI接入测试必须先解决“上下文对齐”问题“想让你的自动化测试接入AI,这一步必须要有。”——这句话在最近几个技术群和内部分享会上被反复提起,但多数人听完只记住了“要上AI”,却忽略了那个…

2026/10/19 5:35:24 阅读更多 →
深度学习面部表情识别实战:Fer2013数据集与CNN/ResNet源码解析

深度学习面部表情识别实战:Fer2013数据集与CNN/ResNet源码解析

简介:基于深度学习的面部表情识别毕业设计项目包,评审分98分,面向计算机相关专业正在完成毕业设计、课程设计或期末大作业的学生,也适合需要真实项目练手的深度学习和人工智能学习者。压缩包共36个文件,大小约446MB&am…

2026/10/19 5:35:24 阅读更多 →
分页查询接口实战:从MySQL优化到数据权限设计

分页查询接口实战:从MySQL优化到数据权限设计

1. 需求拆解与接口设计思路先说下背景。我手上的项目是一个面向个人用户的成长管理类应用,里面有一个核心模块叫“学习计划”,用户可以创建自己的学习计划,比如“三个月完成英语词汇量突破”、“每天刷一道算法题”之类的,然后系统…

2026/10/19 5:34:24 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →