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

Redis缓存穿透、击穿、雪崩介绍以及解决方案

一、缓存穿透

1.1 什么是缓存穿透

指的是,外部进来的请求,查询一个不存在的数据。Redis中没有,数据库中也没有,这时候如果外部恶意大量请求,所有请求会直接查询数据库,导致数据库崩溃

1.2 解决方案

1.2.1 方案一:缓存空数据

缓存空数据到redis中,比如恶意请求查询编号为1的用户,我查询数据库后发现不存在,就直接在redis中添加键值对:{key: 1, value: null},这样外部再次大量请求也会直接请求在redis上,不会导致数据库异常

优点:简单

缺点:1、如果有大量的随机查询,比如查询编号为1,2,3,4,5......到一万亿的用户,我都保存一个键为编号,值为null的数据,那么对redis的内存压力也是很大的,保存了太多无用数据

2、如果编号为2的用户本来不存在,我现在在redis中设置了一个null的值;如果这个时候真的添加了这个编号为2的用户,那么外部查询也查询不到了:数据不一致

1.2.2 方案二:布隆过滤器

布隆过滤器是指,将键经过多次hash之后以0和1的数组格式,保存在一个位图(bitmap)中,一个请求进来,先把请求中查询的键去位图里查询,如果存在,再去查询Redis,如果不存在则连redis都不会去查,直接返回;

优点:位图bitmap占用内存较小,不像缓存空数据那样缓存大量的不需要的key

缺点:1、实现起来复杂,热点数据从数据库查询出来后,也要写入过滤器中

2、存在误判,如果一个不存在的数据,多次hash之后,在位图中的位置可能显示存在此条数据;导致查询数据库,但是总体上影响不大,误判率可自己在写代码时进行控制

二、缓存击穿

2.1 什么是缓存击穿?

当给某一个热点数据,设置了过期时间,当key过期时,恰好这段时间有大量的并发请求进来,那么可能会把数据库压垮

疑问:key过期了,Redis中查询不到,会去数据库查询,查询完成后不是又会写入redis中吗?为什么会导致大量请求到数据库呢?

解答:查询数据库并写入redis也是需要时间的,有些写入redis的结果集,是需要多表查询的结果,比如需要50ms的,甚至几秒钟才能从数据库查询出来的,那么这段时间就太长了

2.2 解决方案

2.2.1 互斥锁

当key过期后,后进来获取该key的第一个线程,在redis中查询不到,未命中;获取一个互斥锁,然后去查询数据库,获取结果后写入缓存,并释放锁;这段时间内,其他所有线程未命中redis中的数据,尝试获取锁失败(因为锁被线程1拿到了),导致获取锁的等待

优点:强一致性,数据一定是最新最正确的

缺点:要等到线程1查询到,写入redis中并释放锁之后,其他线程才能查询这条键值对的数据

2.2.2 逻辑过期

热点key不设值过期时间,而是加一个逻辑过期时间的字段,用来描述这整条数据是否逻辑过期;

当某个线程1拿到这条数据后,发现逻辑过期时间,已经过期,那么会新开一个线程2去进行缓存重建;而线程1不等待缓存重建的结果,直接将过期的数据返回回去

如果此时有更多的线程3来获取key发现过期,尝试获取锁失败后,会直接返回过期的数据,并不会开启新线程来进行缓存重建,因为只需要一个线程2进行缓存重建就可以了

当线程2缓存重建完成后,再之后的线程4就能获取到最新的数据了

优点:高可用(不管数据一致不一致,先返回了再说),性能优

缺点:不能保证数据绝对一致

三、缓存雪崩

3.1 什么是缓存雪崩?

是指同一时间大量的缓存key同时失效,或者Redis服务宕机,导致大量请求打到数据库,导致数据库压力巨大

3.2 解决方案

3.2.1 不同的过期时间

给不同的key设置不同的过期时间,可随机设置过期时间

3.2.2 Redis集群部署

利用Redis集群提高服务的高可用性,例如哨兵模式、集群模式等

3.2.3 降级限流策略

在redis之前添加降级限流策略,比如nginx、spring cloud gateway等,可以同时作为缓存穿透、击穿、雪崩的保底策略,不止是防范缓存雪崩

3.2.4 添加多级缓存

在redis之前,使用其他caffeine缓存等来做一级缓存,Redis作为二级缓存

附上《缓存三兄弟》及其解决方案打油诗一首:

穿透无中生有key,布隆过滤null隔离

缓存击穿过期key,锁与非期解难题

雪崩大量过期key,过期时间要随机

                                        --黑马程序员

注:其中的“锁与非期解难题”中的非期指的是逻辑过期


http://www.kler.cn/a/533493.html

相关文章:

  • 用python实现进度条
  • 【分布式架构理论3】分布式调用(2):API 网关分析
  • 一文讲解Spring中应用的设计模式
  • 了解比特币
  • 【实践案例】基于大语言模型的海龟汤游戏
  • Unity GetLocalizedString()失效问题
  • vscode 设置在编辑器的标签页超出可视范围时自动换行(workbench.editor.wrapTabs)
  • SpringBoot 基于个性化定制的智慧校园管理系统设计与开发 - 论文、开题报告
  • 搭建Python环境:为量化交易做准备
  • Linux之安装MySQL
  • Oh3.2项目升级到Oh5.0(鸿蒙Next)具体踩坑记录二
  • 正则表达式详细介绍
  • 题解:洛谷 P1744 采购特价商品
  • 算法随笔_39: 最多能完成排序的块_方法2
  • embeddingbag词袋
  • 协议的种类
  • RNN/LSTM/GRU 学习笔记
  • java进阶知识点
  • 软件测试丨PyTorch 图像目标检测
  • CSS的媒体查询语法
  • Zabbix7.0安装(Ubuntu24.04+LNMP)
  • ES面试题
  • 【学Rust写CAD】4 相对坐标系详解与实现要素概览
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-autobackend.py
  • WebSocket协议里客户端发送给服务器的数据会用4字节的掩码循环异或的分析
  • UE5 创建自定义工具上下文的方法