Redis缓存雪崩缓存击穿缓存穿透

news2024/11/8 20:35:26

Redis缓存雪崩&缓存击穿&缓存穿透

  • 一 缓存更新策略
  • 二 缓存雪崩
  • 三 缓存击穿
  • 四 缓存穿透

一 缓存更新策略

目前redis缓存更新存在3种主流策略,分别是:内存淘汰、超时剔除、主动更新。
1、内存淘汰

LRU/LFU/FIFO算法剔除:例如maxmemory-policy(到了最大内存,对应的应对策略)。

​LRU -Least Recently Used,没有被使用时间最长的。

​LFU -Least Frequenty User,一定时间段内使用次数最少的。

FIFO -First In First Out,先进先出。

LIRS (Low Inter-reference Recency Set)是一个页替换算法,相比于LRU(Least Recently Used)和很多其他的替换算法,LIRS具有较高的性能。这是通过使用两次访问同一页之间的距离(本距离指中间被访问了多少非重复块)作为一种尺度去动态地将访问页排序,从而去做一个替换的选择。

# LRU配置
maxmemory-policy:volatile-lru

(1)noeviction: 如果内存使用达到了maxmemory,client还要继续写入数据,那么就直接报错给客户端
(2)allkeys-lru: 就是我们常说的LRU算法,移除掉最近最少使用的那些keys对应的数据,ps最长用的策略
(3)volatile-lru: 也是采取LRU算法,但是仅仅针对那些设置了指定存活时间(TTL)的key才会清理掉
(4)allkeys-random: 随机选择一些key来删除掉
(5)volatile-random: 随机选择一些设置了TTL的key来删除掉
(6)volatile-ttl: 移除掉部分keys,选择那些TTL时间比较短的keys

# LFU配置 Redis4.0之后为maxmemory_policy淘汰策略添加了两个LFU模式:

volatile-lfu:对有过期时间的key采用LFU淘汰算法
allkeys-lfu:对全部key采用LFU淘汰算法
# 还有2个配置可以调整LFU算法:
lfu-log-factor 10
lfu-decay-time 1
# lfu-log-factor可以调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。
# lfu-decay-time是一个以分钟为单位的数值,可以调整counter的减少速度

一致性:差
维护成本:无

2、超时剔除

给缓存数据添加有效时间,到期后自动删除缓存。下次查询时更新缓存。
一致性:一般
维护成本:低(只用编写一个添加时间的代码)

3、主动更新

编写业务逻辑,在修改数据库的同时,更新缓存。
一致性:好
维护成本:高(需要编写整套业务逻辑代码)

二 缓存雪崩

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

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

在这里插入图片描述
解决方案:

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

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

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

2.互斥锁:当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里),当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
实现互斥锁的时候,最好设置超时时间,不然第一个请求拿到了锁,然后这个请求发生了某种意外而一直阻塞,一直不释放锁,这时其他请求也一直拿不到锁,整个系统就会出现无响应的现象。

3.双 key 策略:我们对redis缓存key值使用两个key,主key会设置过期时间,备用key不会设置过期时间,相当于做了一个副本。
当业务线程访问不到主key时,就返回备用key的缓存数据,在跟新缓存时,同时更新两个key的缓存数据。

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

针对redis故障宕机

构建redis集群:如果 Redis 缓存的主节点故障宕机,从节点可以切换成为主节点,继续提供缓存服务,避免了由于 Redis 故障宕机而导致的缓存雪崩问题。

三 缓存击穿

我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据。

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

在这里插入图片描述
应对缓存击穿可以采取前面说到两种方案:

互斥锁方案:保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

不给热点数据设置过期时间:由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;

四 缓存穿透

当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦缓存恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。

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

在这里插入图片描述
缓存穿透的发生一般有这两种情况:

  • 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
  • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;

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

  • 非法请求的限制;
  • 缓存空值或者默认值;
  • 使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在;

非法请求的限制:当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库。

缓存空值或者默认值:当我们线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

使用布隆过滤器:我们可以在写入数据库数据时,使用布隆过滤器做个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在。

即使发生了缓存穿透,大量请求只会查询 Redis 和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis 自身也是支持布隆过滤器的。

布隆过滤器

布隆过滤器由「初始值都为 0 的位图数组」和「 N 个哈希函数」两部分组成。当我们在写入数据库数据时,在布隆过滤器里做个标记,这样下次查询数据是否在数据库时,只需要查询布隆过滤器,如果查询到数据没有被标记,说明不在数据库中。

布隆过滤器会通过 3 个操作完成标记:

  • 第一步,使用 N 个哈希函数分别对数据做哈希计算,得到 N 个哈希值;
  • 第二步,将第一步得到的 N 个哈希值对位图数组的长度取模,得到每个哈希值在位图数组的对应位置。
  • 第三步,将每个哈希值在位图数组的对应位置的值设置为 1;

总结
缓存异常会面临的三个问题:缓存雪崩、击穿和穿透。

其中,缓存雪崩和缓存击穿主要原因是数据不在缓存中,而导致大量请求访问了数据库,数据库压力骤增,容易引发一系列连锁反应,导致系统奔溃。不过,一旦数据被重新加载回缓存,应用又可以从缓存快速读取数据,不再继续访问数据库,数据库的压力也会瞬间降下来。因此,缓存雪崩和缓存击穿应对的方案比较类似。

而缓存穿透主要原因是数据既不在缓存也不在数据库中。因此,缓存穿透与缓存雪崩、击穿应对的方案不太一样。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生进阶之容器】第二章Controller Manager原理2.4节--Informer机制剖析

1 Informer机制剖析 如上图所示,client-go 包中一个非常核心的工具就是 informer,informer 可以让与 kube-apiserver 的交互更加优雅。 Informer的主要作用包括如下两个方面: 同步数据到本地缓存。Informer 会不断读取 Delta FIFO 队列中的 Object,在触发事件回调之…

MySQL8.0锁情况排查

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。作者: 杨延昭文章来源:GreatSQL社区投稿 在数据库中,除传统的计算资源(CPU、RAM、IO)的争用…

【C语言】-关于指针的知识你真的都知道了??快进来看看这里面的指针会让你眼前一亮

🎇作者:小树苗渴望变成参天大树 🎊作者宣言:认真写好每一篇博客 🎉 作者gitee:link 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 指针进阶💦前言💖一、…

MYSQL 数据行列交换(交换数据) 存储过程实现

行列转换的存储过程 初始图: 效果图: 实现过程: 1:建表、建数据 CREATE TABLE changeprice ( id bigint(20) NOT NULL auto_increment, sid bigint(20) NOT NULL, datecreated timestamp NOT NULL defaultCURRENT_TIMESTAMP…

nvue2中使用axios和插槽

一、组件的生命周期1、组件的生命周期经历的阶段:(1)创建阶段:beforeCreate、created、beforeMount、mounted(2)运行阶段:beforeUpdate、update(3)销毁阶段:2…

C语言二维数组和二重指针详解

二维数组 一个二维数组,在本质上,是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组,形式如下: type arrayName [x][y]; 这个表示,有x个一维数组,每个一维数组的元素个数是y个。 声明示例&#xff1…

手写VITE-MockJS插件

mockJS是什么 mockJS是模拟接口数据,拦截客户端的请求的一个工具。 vite插件编写流程 pnpm init 初始化 pnpm install vite -D 安装Vite 配置package.json文件中的脚本 "scripts": {"dev": "vite","build": "vite…

K8s集群离线安装-kubeadm-详细篇

1、部署k8s的两种方式:kubeadm 和二进制源码安装 #本次实验采用的部署Kubernetes方式: kubeadm Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。2、环境准备 #服务器要求: 建…

JavaSE学习day1_02, JDK安装

1.4 环境变量 1.4.1 为什么配置环境变量 在初次学习编程的时候,环境变量我们经常提到,但是环境变量到底是什么?是干嘛的?弄清楚这些问题很重要. 如果我们想要在CMD的任意路径下都可以打开任意的软件,那么就需要把软件的路径配置到环境变量当中。 为了便于大家…

Zotero | 快速入门

文章目录0. 前言1. Zotero快速入门1.1 下载Zotero和Connector2.2 联动sci-hub实现英文文献批量下载2.3 英文文献翻译2.4 中文文献元数据识别2.5 Zotero其他配置2.5.1 语言切换2.5.2 数据存储位置更改参考0. 前言 Zotero是一款自由及开放源代码的文献管理软件,管理书…

告别2022,喜迎2023

2022只剩下最后几天,新的一年即将拉开序幕。你的2022,是苦尽甘来、柳暗花明,还是安适如常、平安喜乐?你会用什么词来形容你的2022,你期待的2023又是什么样的呢? 时光荏苒,岁月悠悠,转眼间,202…

猿代码超算实习生计划之编程语言分析

编程语言特别多,很多同学都特别纠结以后到底选择哪一种编程语言,才好找高薪实习和工作。 其实编程语言没有好坏之分。很多同学选择未来就业和实习方向时很多也都是参考的薪资和岗位数量。就像前几年很多人选的前端、现在卷到不行的Java、还有今年连实习…

【Cortex-A7核PWM实验】

Cortex-A7核PWM实验 ---蜂鸣器、风扇、震动马达PWN概念PWM硬件电路图如何产生PWM方波捕获/比较寄存器工作原理代码实现PWN概念 PWM是指脉冲宽度调制(Pulse Width Modulation),是一种常用的模拟信号转换为数字信号的方法。 1.脉冲&#xff1a…

C#WinForm实现多语言切换

因项目需要,所以在网上找了一些方法实现了该功能,本文也是做一个总结和记录。使用resx文件实现Winform多语言切换,以实现简体中文、英文、泰语的切换为例。如果后续需要增加其它语言的切换,只需要按照步骤重复操作即可。 效果图如…

【Kotlin】函数 ⑨ ( Kotlin 语言中的闭包概念 | Java 语言中函数作为参数的替代方案 )

文章目录一、闭包概念二、Java 中函数作为参数的替代方案 ( 匿名内部类 )一、闭包概念 匿名函数 就是 Lambda 表达式 , 同时也是 闭包 , 三者的是相同的概念 ; 闭包意义 : 在 Java 中 , 通过 Package 包 , Class 类 , 将作用域区分开 , 将变量 定义在 不同的 包 或 类中 , 可…

阿里云创世纪之盘古传奇

文章目录飞天(Apsara)云计算平台简介面向私有云的Apsara Stack盘古横空出世盘古的架构盘古基本介绍盘古API基于C语言的SDK基于命令行的文件操作接口pu盘古中的目录和文件盘古目录盘古中的文件盘古中的文件类型盘古应用场景盘古的功能特性盘古主要性能盘古的数据安全盘古的边界盘…

Docker - Docker网络

一、Docker网络介绍 Docker是基于Linux Kernel(内核)的namespace,CGroups,UnionFileSystem等技术封装成的一种自定义容器格式,从而提供了—套虚拟运行环境。 1、namespace:用来做隔离的,比如pid[进程].、…

Java多线程案例之阻塞队列

文章目录一. 认识阻塞队列1. 什么是阻塞队列2. 生产者消费者模型3. 标准库中阻塞队列类二. 基于循环队列实现的简单阻塞队列1. 循环队列的简单实现2. 阻塞队列的简单实现一. 认识阻塞队列 1. 什么是阻塞队列 阻塞队列本质上还是一种队列, 和普通队列一样, 遵循先进先出, 后进…

291. 蒙德里安的梦想(状态压缩dp详解)

求把 NM 的棋盘分割成若干个 12 的长方形,有多少种方案。 例如当 N2,M4 时,共有 5 种方案。当 N2,M3 时,共有 3 种方案。 如下图所示: 输入格式 输入包含多组测试用例。 每组测试用例占一行&#xff0c…

龙芯机器JDK安装和配置

龙芯机器:[rootlocalhost j2sdk-image]# cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c4 Loongson-3A R4 (Loongson-3A4000) 1800MHz龙芯机器JDK安装和配置下载地址:http://www.loongnix.cn/zh/api/java/选择JDK8,选择MIPS64进行下…