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

Redis缓存击穿、雪崩、穿透

1. 缓存击穿

1.1 触发原因

redis中,缓存击穿的含义是指,当某个热点数据的缓存突然失效,大量请求直接访问数据库的情况:

    public Result<Data> findProductData(String dataId) {//在Redis中查询Object o = redisTemplate.opsForValue().getKey(dataId);if(o != null) {return new Result<>((Data)o);}//在数据库中查询Data data = productMapper.findById(dataId);if(data == null) {return new Result<>(null);}//把数据存入RedisredisTemplate.opsForValue().set(dataId, data, Duration.ofHours(2L);return new Result<>(data);}

上面代码中,如果key失效了,那么大量的并发请求就会直接访问数据库,就像是redis被击穿了,所以形象的称为缓存击穿。

1.2 解决方案:
  1. 设置永不过期:经过上面介绍,我们知道,缓存击穿是由于key失效引起的,那么我们将key设置为永不过期就可以解决这个问题,当然,redis的内存不是无限的,所有我们不能把所有key都设置为永不过期,具体的我们可以检测key的访问频率,把 "足够热门" 的key设置为永不过期即可。
  2. 加锁排队:发生缓存击穿后,会突然有大量请求并发访问数据库,那么我们可以在缓存击穿后通过加锁的方式,让请求串行到达数据库
    public Result<Data> findProductData(String dataId) {//在Redis中查询Object o = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}synchronized(this) {//双重检测,其它线程可能已经把key又存入rediso = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}//在数据库中查询Data data = productMapper.findById(dataId);if(data == null) {return new Result<>(null);}//把数据存入RedisredisTemplate.opsForValue().set(dataId, data, Duration.ofHours(2L));return new Result<>(data);}}

2. 缓存雪崩

2.1 触发原因

当缓存中多个key集中失效时,大量请求直接访问数据库,造成数据库压力暴增,甚至宕机

2.2 解决方案

通过上面介绍我们知道,导致缓存雪崩的原因是多个key集中失效,那么我们就可以对症下药,随机key的失效时间,尽量避免集中失效的情况:

public Result<Data> findProductData(String dataId) {//在Redis中查询Object o = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}synchronized(this) {//双重检测,其它线程可能已经把key又存入rediso = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}//在数据库中查询Data data = productMapper.findById(dataId);if(data == null) {return new Result<>(null);}//设置随机失效时间Duration duration = Duration.ofHours(2L).plus(Duration.ofSeconds((int)(Math.random() * 100)));//把数据存入RedisredisTemplate.opsForValue().set(dataId, data, duration);return new Result<>(data);}}

3. 缓存穿透

3.1 触发原因

缓存穿透是指,请求访问了数据库中不存在的数据,数据不存在也就代表缓存中不可能有,就会直接访问数据库,这种情况可能是服务器受到了攻击。

3.2 解决方案

把空数据也缓存到redis:在之前的代码中,我们对于不存在的数据不会做缓存,那么如果收到大量访问不存在数据的请求就会导致数据库压力过大,于是我们可以去掉判断让不存在数据key也能缓存到redis:

public Result<Data> findProductData(String dataId) {//在Redis中查询Object o = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}synchronized(this) {//双重检测,其它线程可能已经把key又存入rediso = redisTemplate.opsForValue().get(dataId);if(o != null) {return new Result<>((Data)o);}//在数据库中查询Data data = productMapper.findById(dataId);//设置随机失效时间Duration duration = Duration.ofHours(2L).plus(Duration.ofSeconds((int)(Math.random() * 100)));//把数据存入RedisredisTemplate.opsForValue().set(dataId, data, duration);return new Result<>(data);}}

这里也可以使用布隆过滤器,把不存在数据的key记录下来,每次请求时先判断布隆过滤器中有无该key,如果没有则继续在redis或数据库中查询,查询到空数据则把key记录到布隆过滤器中,表示这个key并无数据,可以类比黑名单的含义。


文章转载自:

http://5XHNulf5.Lsjtq.cn
http://WAmYdF4C.Lsjtq.cn
http://1cE9K4nk.Lsjtq.cn
http://ycRH50g0.Lsjtq.cn
http://jkdbTjxb.Lsjtq.cn
http://GUBDWe7B.Lsjtq.cn
http://nJnngGqO.Lsjtq.cn
http://PaA6oWHF.Lsjtq.cn
http://tFwRELX9.Lsjtq.cn
http://zuzJgWKR.Lsjtq.cn
http://84I1UHrD.Lsjtq.cn
http://WrQS2sTW.Lsjtq.cn
http://ldiz6Nds.Lsjtq.cn
http://Ncr2U2EQ.Lsjtq.cn
http://lQQdCflJ.Lsjtq.cn
http://KxSslgst.Lsjtq.cn
http://3W4wB0Zs.Lsjtq.cn
http://dTpE2JHF.Lsjtq.cn
http://sXMO3gkU.Lsjtq.cn
http://nbq78v9t.Lsjtq.cn
http://qEDOvZ47.Lsjtq.cn
http://anGyv4l6.Lsjtq.cn
http://IbWw32pN.Lsjtq.cn
http://klEHjnnw.Lsjtq.cn
http://u6J1sbth.Lsjtq.cn
http://BzeqBcKe.Lsjtq.cn
http://Dk3JhjcJ.Lsjtq.cn
http://PIQkV8mS.Lsjtq.cn
http://Ei9FDrKc.Lsjtq.cn
http://eyh3HNWF.Lsjtq.cn
http://www.dtcms.com/a/374021.html

相关文章:

  • Go正则表达式实战指南
  • 保持元素可见但不可访问的方法: `inert`
  • ClaudeCode稳定备用方案:API接入详解
  • 【教程】Ansible 环境部署
  • Linux-信号量
  • 3000h CeB₆ 灯丝加持的 Phenom XL G3 扫描电镜技术亮点
  • C语言scanf函数的空格问题
  • 【Git】使用GitCode的全局配置
  • 论文阅读:ACL 2023 MEETINGQA: Extractive Question-Answering on Meeting Transcripts
  • Docker Compose healthcheck介绍(监控容器中服务的实际健康状态)数据库健康检查pg_isready
  • 鸿蒙NEXT中SQLite数据库全面实战指南
  • Go语言文件处理实战指南
  • 【鸿蒙(openHarmony)ETS语言实现视频播放器的详细步骤】
  • SpringBoot教程(三十一) | SpringBoot集成SpringSecurity权限框架
  • 第四十九篇-Tesla P40+Fastllm+Hunyuan-A13B-Instruct+CPU+GPU混合部署推理
  • 安装docker遇到的问题1: [Errno 14] curl#35 - “TCP connection reset by peer“
  • 【Debug日志 | 模型loss不降】
  • 千呼万唤始出来 谭维维音乐会官宣北京
  • 如何给智能家居注入“温度”?世强详解无线通信与AI算力背后的创新方案​
  • 金智维的智能财务管理工具有哪些?
  • 嵌入式 - ARM(1):ARM体系结构
  • 关于对鱼眼相机图片进行畸变校正的两种思路
  • mybatis-plus原生的批量插入
  • 设计模式 概述
  • SQL 注入与防御-第九章:平台层防御
  • SCADA与DCS深度集成实践:打破工厂“信息孤岛”,让实时控制更智能
  • 小学挫折教育主题班会PPT课件模板下载
  • 深入理解 MyBatis-Plus 的 `BaseMapper`
  • YOLOv8 TensorRT C++部署实战详解:从XMake构建到推理流水线
  • HTML HTML基础(3)