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

news/2025/2/6 8:31:41/

一、缓存穿透

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.ppmy.cn/news/1569750.html

相关文章

32. C 语言 安全函数( _s 尾缀)

本章目录 前言什么是安全函数?安全函数的特点主要的安全函数1. 字符串操作安全函数2. 格式化输出安全函数3. 内存操作安全函数4. 其他常用安全函数 安全函数实例示例 1:strcpy_s 和 strcat_s示例 2:memcpy_s示例 3:strtok_s 总结 …

排序算法--计数排序

唯一种没有比较的排序(指没有前后比较,还是有交换的)。统计每个元素出现的次数,直接计算元素在有序序列中的位置,要求数据是整数且范围有限。适用于数据为小范围整数(如年龄、成绩),数据重复率较高时效率更优。可用于小…

oracle: 数据操纵语言DML/批量更新

SQL(Structured Query Language,结构化查询语言)是一种用于管理和操作关系数据库的标准编程语言。 sql分类: DML基本语法 DML是“Data Manipulation Language”的缩写, 即数据操纵语言 用于对数据库中的数据进行插入、更新、删除(即增删改…

Ubuntu 上可以安装ms sqlserver?

是的,Microsoft SQL Server 可以安装在 Ubuntu 上。自 SQL Server 2017 版本起,Microsoft 提供了对 Linux 的支持,包括 Ubuntu。以下是详细的步骤,介绍如何在 Ubuntu 上安装 SQL Server。 步骤 1:导入 Microsoft GPG …

【大数据技术】搭建完全分布式高可用大数据集群(Scala+Spark)

搭建完全分布式高可用大数据集群(Scala+Spark) scala-2.13.16.tgzspark-3.5.4-bin-without-hadoop.tgz注:请在阅读本篇文章前,将以上资源下载下来。 写在前面 本文主要介绍搭建完全分布式高可用集群Spark的详细步骤。 注意: 统一约定将软件安装包存放于虚拟机的/softwa…

安卓(android)饭堂广播【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的(如果代码有错漏,可查看源码) 1.熟悉广播机制的实现流程。 2.掌握广播接收者的创建方式。 3.掌握广播的类型以及自定义官博的创建。 二、实验条件 熟悉广播机制、广播接收者的概念、广播接收者的创建方式、自定广播实现方式以及有…

从零开始学习安时积分法(STM32实现程序)

在STM32微控制器上实现安时积分法(Coulomb Counting)来估算电池的SOC(State of Charge),需要完成以下几个步骤: 硬件配置: 使用STM32的ADC模块测量电池的电流。使用定时器模块进行时间积分。配置…

【Leetcode 热题 100】1143. 最长公共子序列

问题背景 给定两个字符串 t e x t 1 text_1 text1​ 和 t e x t 2 text_2 text2​,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 0 0。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变…