Redis缓存雪崩,击穿,穿透问题

缓存雪崩、击穿、穿透、发生的背景

​ 作者最近在写一个社区论坛项目,初始设想将论坛里用户发布的帖子内容存到数据库中,当用户访问论坛里的帖子时,帖子信息都从数据库中查。众所周知数据库的帖子数据是存在磁盘中的,而磁盘读写数据是计算机里最慢的(读取数度:寄存器>cpu高速缓存>内存>磁盘),所以为了避免用户直接访问数据库,我们会用redis做缓存层,将热门帖子存起来;当用户访问论坛时优先看到时存在redis缓存层的热门帖子(这似乎就是缓存预热)。

​ 因为 Redis 是内存数据库,我们可以将数据库的数据缓存在 Redis 里,相当于数据缓存在内存,内存的读写速度比硬盘快好几个数量级,这样大大提高了系统性能
在这里插入图片描述

引入了缓存层,就会有缓存异常的三个问题,分别是缓存雪崩、缓存击穿、缓存穿透

缓存雪崩、击穿、穿透会导致什么结果?

缓存雪崩、击穿、穿透发生后数据库很容易被高并发的请求冲垮

一般来说,MySQL能够处理大约每秒数百到数千个并发请求,如果超过就可能会崩溃

什么是雪崩、击穿、穿透?

在这里插入图片描述

缓存雪崩

​ 通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存。
在这里插入图片描述

​ 那么,当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。

​ 拿项目场景举例, 当Redis中缓存的大量帖子信息在同一时间过期失效或者redis故障宕机,如果有数以万计的用户访问论坛社区,在发现页给用户推荐的帖子无法从redis中读取,只能直接访问数据库,从而导致数据库压力骤增,严重时会导致数据库宕机,整个系统崩溃,

缓存雪崩的解决方案

发生缓存雪崩的原因有两个

  • 大量数据同时过期;
  • Redis 故障宕机;
大量数据同时过期

针对大量数据同时过期而引发的缓存雪崩问题,常见的应对方法有下面这几种:

  • 均匀设置过期时间;
  • 互斥锁;
  • 后台更新缓存;

1. 均匀设置过期时间

如果要给缓存数据设置过期时间,应该避免将大量的数据设置成同一个过期时间。我们可以在对缓存数据设置过期时间时,给这些数据的过期时间加上一个随机数,这样就保证数据不会在同一时间过期。

2. 互斥锁

当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里),当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

实现互斥锁的时候,最好设置超时时间,不然第一个请求拿到了锁,然后这个请求发生了某种意外而一直阻塞,一直不释放锁,这时其他请求也一直拿不到锁,整个系统就会出现无响应的现象。

3. 后台更新缓存

业务线程不再负责更新缓存,缓存也不设置有效期,而是让缓存“永久有效”,并将更新缓存的工作交由后台线程定时更新

事实上,缓存数据不设置有效期,并不是意味着数据一直能在内存里,因为当系统内存紧张的时候,有些缓存数据会被“淘汰”,而在缓存被“淘汰”到下一次后台定时更新缓存的这段时间内,业务线程读取缓存失败就返回空值,业务的视角就以为是数据丢失了。

解决上面的问题的方式有两种。

第一种方式,后台线程不仅负责定时更新缓存,而且也负责频繁地检测缓存是否有效,检测到缓存失效了,原因可能是系统紧张而被淘汰的,于是就要马上从数据库读取数据,并更新到缓存。

这种方式的检测时间间隔不能太长,太长也导致用户获取的数据是一个空值而不是真正的数据,所以检测的间隔最好是毫秒级的,但是总归是有个间隔时间,用户体验一般。

第二种方式,在业务线程发现缓存数据失效后(缓存数据被淘汰),通过消息队列发送一条消息通知后台线程更新缓存,后台线程收到消息后,在更新缓存前可以判断缓存是否存在,存在就不执行更新缓存操作;不存在就读取数据库数据,并将数据加载到缓存。这种方式相比第一种方式缓存的更新会更及时,用户体验也比较好。

ps业务线程不再负责更新缓存,缓存也不设置有效期,而是让缓存“永久有效”,并将更新缓存的工作交由后台线程定时更新

事实上,缓存数据不设置有效期,并不是意味着数据一直能在内存里,因为当系统内存紧张的时候,有些缓存数据会被“淘汰”,而在缓存被“淘汰”到下一次后台定时更新缓存的这段时间内,业务线程读取缓存失败就返回空值,业务的视角就以为是数据丢失了。

解决上面的问题的方式有两种。

第一种方式,后台线程不仅负责定时更新缓存,而且也负责频繁地检测缓存是否有效,检测到缓存失效了,原因可能是系统紧张而被淘汰的,于是就要马上从数据库读取数据,并更新到缓存。

这种方式的检测时间间隔不能太长,太长也导致用户获取的数据是一个空值而不是真正的数据,所以检测的间隔最好是毫秒级的,但是总归是有个间隔时间,用户体验一般。

第二种方式,在业务线程发现缓存数据失效后(缓存数据被淘汰),通过消息队列发送一条消息通知后台线程更新缓存,后台线程收到消息后,在更新缓存前可以判断缓存是否存在,存在就不执行更新缓存操作;不存在就读取数据库数据,并将数据加载到缓存。这种方式相比第一种方式缓存的更新会更及时,用户体验也比较好。

ps:上面两种方法的缓存数据失效包含两种情况

  • 缓存淘汰
  • 缓存从未存在

Redis 故障宕机

针对 Redis 故障宕机而引发的缓存雪崩问题,常见的应对方法有下面这几种:

  • 服务熔断或请求限流机制;
  • 构建 Redis 缓存高可靠集群;

缓存击穿

如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。

比如:社区论坛里的关于重庆胖猫的帖子热度极高,经常被用户频繁搜索访问,但该类帖子在某时间过期,就会导致该时间内大量用户直接从数据库中查询帖子信息,使数据库崩溃

在这里插入图片描述

应对缓存击穿可以采取前面说到两种方案:

  • 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
  • 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时

缓存穿透

​ 当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。

​ 缓存雪崩和击穿和认为是缓存过期时间设置过于集中和没有对热点数据缓存过期失效做预防。但都可以通过恢复缓存(即将数据库中的数据刷新到缓存)来减少对数据库的访问。发生这两个缓存问题可以把锅甩到开发者头上。

发生缓存穿透可能有两种情况

  • 由于业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据,当用户访问该误删数据库时发生缓存击穿

  • 由于黑客恶意攻击,故意大量访问某些读取不存在数据的业务,导致数据库崩溃发生缓存穿透

第一种是开发者的锅,第二种是用户的锅

应对缓存穿透的方案,常见的方案有三种。

  • 第一种方案,非法请求的限制

​ 设置中间件判断每个请求参数是否存在

  • 第二种方案,缓存空值或者默认值

      	如果发现缓存穿透现象,就在缓存设置空值或默认值,下次同样请求来时直接通过缓存返回
    
  • 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在

缓存穿透相比较与缓存雪崩、击穿对数据库的危害较小

缓存穿透对数据库的影响总体来说没有缓存雪崩和击穿的大,如果是由于大量恶意攻击,会产生较大的影响和缓存击穿的影响有点类似

接通过缓存返回

  • 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在
缓存穿透相比较与缓存雪崩、击穿对数据库的危害较小

缓存穿透对数据库的影响总体来说没有缓存雪崩和击穿的大,如果是由于大量恶意攻击,会产生较大的影响和缓存击穿的影响有点类似

但在普通情况下的误删数据库或用户误访问非法数据,由于这种请求数据通常是少数,因此它对系统的影响相比其他类型的缓存问题较小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/611474.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

串口初始化自己独立的见解--第九天

1.SM0,SM1 我们一般用 8位UART,波特率可变 (方式1的工作方式) SCON :SM2 一般不用,SM0 0 ,SM1 1 PCON : 有两位 我们不动它,不加速,初始值 TMOD:8位自动重装定时器&#xff0…

ADS基础教程11 - TouchStone文件的导出及导入

目录 一、 T o u c h S t o n e 介绍 \color{#4285f4}{ \mathbf{ 一、TouchStone介绍}} 一、TouchStone介绍 二、文件导出、导入方式 \color{#4285f4}{ \mathbf{ 二、文件导出、导入方式}} 二、文件导出、导入方式1.原理图操作1)原理图中导出2.原理图中导入 3.DDW中…

Python图形复刻——绘制母亲节花束

各位小伙伴,好久不见,今天学习用Python绘制花束。 有一种爱,不求回报,有一种情,无私奉献,这就是母爱。祝天下妈妈节日快乐,幸福永远! 图形展示: 代码展示: …

详解分布式锁

知识点: 单体锁存在的问题: 单体锁,即单体应用中的锁,通过加单体锁(synchronized或RentranLock)可以保证单个实例并发安全 单体锁是JVM层面的锁,只能保证单个实例上的并发访问安全 如果将单…

消除试卷手写笔迹的软件免费的有哪些?这几款都不错

消除试卷手写笔迹的软件免费的有哪些?在数字化学习的浪潮中,学生们越来越频繁地利用电子设备来完成学习任务。然而,当纸质试卷需要被数字化并再次利用时,如何高效地消除手写笔迹便成为了一个有待解决的问题。那么,今天…

【Linux】简易进度条的实现

🎉博主首页: 有趣的中国人 🎉专栏首页: Linux 🎉其它专栏: C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好,本片文章将会讲解Linux中进度条的实现的相关内容。 如果看到最后您觉得这篇文章写得…

coherence protocal基础

一致性整体抽象 coherence protocol是通过保证如下的两点invariants,来实现一致性的; SWMR invariant, 对于任何一个地址,任何时刻,都只会有一个core写,可能会有多个core读;Data-value invariant&#xf…

每天五分钟深度学习:数学中的极值

本文重点 在数学领域中,极值是一个极其重要的概念,它不仅在纯数学理论研究中占据核心地位,而且在工程、物理、经济等实际应用领域也发挥着不可替代的作用。极值问题涉及函数的最大值和最小值,是微积分学中的一个基本问题。本文旨在详细介绍数学中的极值概念、性质、求解方…

Python查询PostgreSQL数据库

哈喽,大家好,我是木头左! Python与PostgreSQL的连接 需要了解如何在Python中连接到PostgreSQL数据库。这通常涉及到使用一个库,如psycopg2,它是Python中用于PostgreSQL的最流行的适配器。安装psycopg2非常简单&#x…

202466读书笔记|《一天一首古诗词》——借问梅花何处落,风吹一夜满关山

202466读书笔记|《一天一首古诗词》——借问梅花何处落,风吹一夜满关山 上册下册 《一天一首古诗词》作者李锡琴,蛮早前加入书架的已购买书籍,这次刚好有点时间,利用起来读完。 赏析没有细看,只读了诗词部分&#xff0…

Cocos creator实现《战机长空》关卡本地存储功能

Cocos creator实现《战机长空》关卡本地存储功能 Cocos creator在开放小游戏过程中,经常会出现设置关卡,这里记录一下关卡数据本地存储功能。 一、关卡设置数据 假如我们有关卡数据如下, let settings [ { level: 1, // 第1关 score: 0,…

uniapp的app端推送功能,不使用unipush

1&#xff1a;推送功能使用htmlPlus实现&#xff1a;地址HTML5 API Reference (html5plus.org) 效果图&#xff1a; 代码实现&#xff1a; <template><view class"content"><view class"text-area"><button click"createMsg&q…

Spring框架学习笔记(一):Spring基本介绍(包含IOC容器底层结构)

1 官方资料 1.1 官网 https://spring.io/ 1.2 进入 Spring5 下拉 projects, 进入 Spring Framework 进入 Spring5 的 github 1.3 在maven项目中导入依赖 <dependencies><!--加入spring开发的基本包--><dependency><groupId>org.springframework<…

SpringBoot集成微信支付V3版本流程(商户平台篇)

一、前言 微信支付账号类型分为商户平台和合作伙伴平台&#xff0c;今天主要是梳理商品平台微信支付流程。 商品平台文档地址&#xff0c;(在接入前建议仔细阅读这份文档&#xff0c;会少走很多弯路!!!) 小程序下单 - 小程序支付 | 微信支付商户文档中心 二、接入流程 以下…

qml 和 c++类的数据交互

1、 新建一个需要交互的C++类 1)添加QObject头文件 2)添加自QObject的继承 3)添加Q_OBJECT宏 4)使用Q_PROPERTY,定义两个交互的属性,并设置读写的方法和变更属性的信号。 5)添加方法、槽函数和变量 2、在main.cpp中添加实例化对象的QML上下文 1)添加需要QML交互的…

多个.C文件被编译为一个可执行文件的详细过程

多个.C文件被编译为一个可执行文件的详细过程 文章目录 多个.C文件被编译为一个可执行文件的详细过程前言一、一个.C文件的编译过程二、多个.C文件的链接过程1.文件信息2.链接过程3.makefile 总结 前言 C语言经典的 “hello world ” 程序从编写、编译到运行&#xff0c;看到屏…

html实现网页插入音频

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要介绍html中 如何插入音乐和视频 视频插入 标签:<video></video> 兼容格式:mp4,因为别的浏览器都有不兼容的格式&#xff0c;唯一对mp4全都兼容。所以尽量使用mp4格式。 属性: 属性属性值…

249 基于matlab的MED、OMEDA、MOMEDA、MCKD信号处理方法

基于matlab的MED、OMEDA、MOMEDA、MCKD信号处理方法。最小熵反褶积(MED)&#xff0c;最优最小熵反卷积调整卷积 (OMEDA),多点最优最小熵解卷积调整&#xff08;Multipoint Optimal Minimum Entropy Deconvolution Adjusted&#xff0c;MOMEDA&#xff09;&#xff0c;最大相关峭…

【Shell脚本】Shell编程之循环语句

目录 一.循环语句 1.for语句的结构 1.1.格式 1.2.实操案例 案例1. 案例2. 案例3. 案例4. 2.while语句的结构 2.1.格式 2.2.实操案例 案例1. 案例2. 案例3. 案例4. 3.until循环命令 3.1.格式 3.2.实操案例 案例1. 二.补充 1.常用转义符 一.循环语句 1.for…

JAVA 双亲委派之一

JAVA 双亲委派之一 JVM类加载流程 java语言系统内置了众多类加载器&#xff0c;从一定程度上讲&#xff0c;只存在两种不同的类加载器&#xff1a;一种是启动类加载器&#xff0c;此类加载由C实现&#xff0c;是JVM的一部分&#xff1b;另一种就是所有其他的类加载器&#xf…