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

从零起步学习Redis || 第九章:缓存雪崩,缓存击穿,缓存穿透三大问题的成因及实战解决方案

前言

在高并发系统中,我们通常会使用 Redis 来做缓存,以减轻数据库压力、提高系统性能。然而,在实际开发中,如果缓存机制设计不当,就容易出现三种经典问题:

  • 缓存雪崩(Cache Avalanche)

  • 缓存击穿(Cache Breakdown)

  • 缓存穿透(Cache Penetration)

这三种问题看起来类似,但根本原因和解决方案却不相同。本文将逐一分析它们的 成因、影响、解决方案及代码实践


 一、缓存雪崩(Cache Avalanche)

 1. 概念

缓存雪崩是指:

在同一时间,大量缓存数据同时过期或缓存服务宕机,导致所有请求直接打到数据库,数据库压力骤增甚至崩溃。

 2. 成因

  • 所有缓存 key 设置了相同的过期时间(如都在凌晨 0 点失效);

  • Redis 宕机;

  • 应用重启或缓存被批量清空。

示例:

商品信息缓存设置为 2 小时失效,2 小时后所有 key 同时过期,大量请求瞬间涌向数据库。

 3. 解决方案

✅ 方案1:给过期时间加随机值(均匀平均过期时间)

避免同一时刻大量 key 同时失效。

int expire = 3600 + new Random().nextInt(600); // 1小时~1小时10分钟
redisTemplate.opsForValue().set("product:" + id, product, expire, TimeUnit.SECONDS);

✅ 方案2:缓存预热

在系统启动或流量高峰前,提前加载热点数据进缓存。

✅ 方案3:服务降级机制

当缓存不可用时,临时返回默认值、兜底数据或提示稍后再试。

✅ 方案4:多级缓存

例如:

  • 一级:本地缓存(Caffeine、Guava)

  • 二级:Redis

✅ 方案5:互斥锁

当大量业务线程请求Redis发现数据不存在(过期),使用互斥锁锁住一个线程(保证同一时刻只有一个线程去拉取数据到Redis),其他线程没有锁就无法请求,只能等待或者返回空值

✅ 方案6:后台更新缓存

数据直接设置为不过期,如果数据库有变化,再更新Redis中的数据

问题:不过期可能会出现内存淘汰,此时如何处理?

答:业务线程发现缓存数据失效后,用消息队列通知后台线程更新缓存


 二、缓存击穿(Cache Breakdown)

 1. 概念

缓存击穿是指:

某个热点 key 在失效的瞬间,有大量并发请求同时访问该 key,缓存未命中,导致瞬间大量请求打到数据库。

 2. 成因

  • 热点 key 过期(例如秒杀商品、首页 banner 等);

  • 瞬间有大量请求访问该热点 key。

 3. 解决方案

✅ 方案1:分布式锁(互斥锁)

防止多个线程同时去加载数据库。

String key = "product:" + id;
String lockKey = "lock:" + key;Object cache = redisTemplate.opsForValue().get(key);
if (cache == null) {if (tryLock(lockKey)) { // 抢到锁Object dbData = queryFromDB(id);redisTemplate.opsForValue().set(key, dbData, 60, TimeUnit.SECONDS);releaseLock(lockKey);} else {Thread.sleep(100); // 没抢到锁的稍等再查缓存return redisTemplate.opsForValue().get(key);}
}
return cache;

✅ 方案2:逻辑过期(永不过期策略)

缓存中保存数据和过期时间字段,过期后后台异步更新,而非直接删除缓存。

✅ 方案3:异步预刷新

使用定时任务在 key 即将过期时提前刷新。


 三、缓存穿透(Cache Penetration)

 1. 概念

缓存穿透是指:

查询一个 缓存和数据库中都不存在的 key,每次请求都绕过缓存直接打到数据库,导致数据库压力过大。

 2. 成因

  • 用户或攻击者请求非法或不存在的 key;

  • 数据库查无此数据,缓存未保存任何结果;

  • 下次相同请求又打到数据库。

示例:

攻击者请求 /product?id=-9999,Redis 没有,数据库也没有。下次再请求又重复打 DB。

 3. 解决方案

✅ 方案1:缓存空对象

查询结果为空时,也写入缓存(可设置较短 TTL)。

Object dbData = queryFromDB(id);
if (dbData == null) {redisTemplate.opsForValue().set("product:" + id, "NODATA", 60, TimeUnit.SECONDS);
} else {redisTemplate.opsForValue().set("product:" + id, dbData, 300, TimeUnit.SECONDS);
}

✅ 方案2:参数校验

对请求参数合法性进行检查,如 ID < 0 或非法字符直接拦截。

✅ 方案3:布隆过滤器(Bloom Filter)

在访问 Redis 之前,先通过布隆过滤器判断 key 是否可能存在。

  • 不存在 → 直接拦截请求;

  • 可能存在 → 再访问 Redis。

if (!bloomFilter.mightContain("product:" + id)) {return null; // 直接拦截
}
return redisTemplate.opsForValue().get("product:" + id);


 四、对比总结

问题类型现象成因解决方案
缓存雪崩大量缓存同时失效,DB 压力暴增同一时间过期、Redis 宕机随机过期时间、预热、降级、多级缓存
缓存击穿热点 key 失效瞬间被并发访问热点 key 过期分布式锁、逻辑过期、异步刷新
缓存穿透查询不存在数据反复访问 DBkey 不存在且无缓存缓存空值、参数校验、布隆过滤器

 五、结语

Redis 缓存的使用是高并发系统中提升性能的关键手段,但如果不处理好缓存的失效机制,系统反而可能因为缓存问题而“自爆”。

http://www.dtcms.com/a/450065.html

相关文章:

  • 手机网站 微信链接网站建设工具
  • 网站建设年度总结客源通app下载
  • 欧美做暧网站jsp可以做网站吗
  • Variational Quantum Eigensolver笔记
  • 操作系统应用开发(二十四)RustDesk 404错误—东方仙盟筑基期
  • 网站菜单样式关于网站策划的文章
  • 做网站多久才会有收益网站打开显示站点目录
  • python异常
  • STM32CubeMonitor使用记录
  • 网站这么做海城seo网站排名优化推广
  • 做网站后的收获宁波seo软件免费课程
  • 网站设计精美案例常见软件开发模型有哪些
  • dedecms 网站还原数据之后 乱码网站开发用什么编程
  • 美发店会员管理软件培训
  • 建设部网站不支持360深圳市南山区住房和建设局网站官网
  • 电子签名法律实务全解析:从合规基础到风险防控的实战指南
  • 1元购网站建设广西壮族自治区市场监督管理局官网
  • 陕西省交通建设集团公司门户网站wordpress站内统计插件
  • PyTorch梯度裁剪与避免Loss为NaN的完整指南
  • 【UE5】新建Editor Standalone Window插件,之前(或当前)创建插件的按钮消失(被顶掉/占用)的问题
  • h5做的网站如何连接数据库wordpress上传图片错误媒体库错误
  • 预约记录关联查询接口说明
  • 免得做网站云浮新增病例详情
  • <从零基础到精通JavaScript>1.1 JavaScript 运行环境
  • 青浦专业网站建设企业网站最下面的那栏叫啥
  • 每日一个C语言知识:C 数据类型
  • 实验二十 GaussDB逻辑备份恢复实验
  • 中英文网站制作wordpress表
  • 开源 网站开发框架seo是一种利用搜索引擎
  • 怎样建设网站空间网站开发中英文版如何写