Redis 缓存深度解析:穿透、击穿、雪崩与预热的全面解读

2024-09-07 13:36

本文主要是介绍Redis 缓存深度解析:穿透、击穿、雪崩与预热的全面解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Redis 缓存深度解析:穿透、击穿、雪崩与预热的全面解读

  • 一 . 什么是缓存 ?
  • 二 . 使用 Redis 作为缓存
  • 三 . 缓存的更新策略
    • 3.1 定期生成
    • 3.2 实时生成
  • 四 . 缓存预热、缓存穿透、缓存雪崩、缓存击穿
    • 4.1 缓存预热
    • 4.2 缓存穿透
    • 4.3 缓存雪崩
    • 4.4 缓存击穿

Hello , 大家好 , 这个专栏给大家带来的是 Redis 系列 ! 本篇文章给大家讲解的是 Redis 的缓存. 在 Redis 缓存系统中 , 缓存穿透、缓存击穿、缓存雪崩和缓存预热是常见的问题 , 它们对系统的性能和稳定性有着重要的影响 . 而缓存穿透、缓存击穿、缓存雪崩和缓存预热又是面试常考问题 , 所以大家一定要仔细认真的阅读 !

在这里插入图片描述
本专栏旨在为初学者提供一个全面的 Redis 学习路径,从基础概念到实际应用,帮助读者快速掌握 Redis 的使用和管理技巧。通过本专栏的学习,能够构建坚实的 Redis 知识基础,并能够在实际学习以及工作中灵活运用 Redis 解决问题 .
专栏地址 : Redis 入门实践

一 . 什么是缓存 ?

Redis 最主要的用途主要有三个方面 :

  1. 存储数据 (内存型数据库)
  2. 缓存 (最常用的场景)
  3. 消息队列 (使用比较少)

缓存的作用就是让我们能够更快地获取到数据 , 一般来说速度快的设备可以给速度慢的设备去做缓存 .

对于硬件的访问速度来说 , 通常情况下是这样的 : CPU 寄存器 > 内存 > 硬盘 > 网络

比较常见的是使用内存来去作为硬盘的缓存 (Redis) , 甚至我们也可以使用硬盘来去作为网络的缓存

使用硬盘来去作为网络的缓存这种场景也是存在的 , 比如 : 浏览器的缓存 , 浏览器通过 HTTP/HTTPS 从服务器上获取到数据 (HTML / CSS / JS / 图片 / 视频 / 音频 / 字体 …) 并且进行展示 , 那像这些体积大而且变化不频繁的数据就可以保存到浏览器本地 , 这就是使用硬盘来去给网络做缓存 .

二 . 使用 Redis 作为缓存

在一个网站中 , 我们通常会使用 Redis 来去作为关系型数据库 (MySQL) 的缓存

为什么一般来说关系型数据库性能都不高 ?

  1. 关系型数据库把数据存储到硬盘上 , 但是硬盘的 IO 速度并不快 , 尤其是随机访问
  2. 如果查询不能命中索引 , 就需要进行表的整个遍历 , 这样就会大大增加硬盘的 IO 次数
  3. 关系型数据库对于 SQL 的执行会做一系列的解析、校验、优化工作
  4. 一些复杂查询 (比如 : 笛卡尔积操作) 效率也会降低

由于关系型数据库效率一般比较低 , 所以能够承担的并发量有限 . 一旦请求数量变多 , 数据库的压力就会变大 , 甚至严重到宕机 .

那如何提高 MySQL 能够承担的并发量呢 ?

  1. 开源 : 引入更多的机器 , 构成数据库集群
  2. 节流 : 引入缓存就是一种节流的方案 , 把一些频繁读取的热点数据保存到缓存中 , 后续查询数据 , 如果缓存中存在就直接返回

三 . 缓存的更新策略

如何知道 Redis 中应该存储哪些数据呢 ? 也就是如何知道哪些数据属于热点数据呢 ?

那我们需要先了解一下缓存的更新策略

3.1 定期生成

首先我们会把访问的数据以日志的形式记录下来 .

通过日志 , 就可以把访问的数据记录下来 , 然后针对这些日志进行统计 , 按照一段时间内数据出现的频率进行降序排序 , 然后排名靠前的数据就可以认为是热点数据 .

那这个热点数据 , 就可以根据当前的统计维度 (每 天/周/月) 来定期更新 , 我们可以写一套离线的流程 (比如使用 Shell / Python … 来去写一些脚本代码) 来进行定时任务的触发 .

这种方式的优点是上述过程实现比较简单 , 过程更可控 , 方便排查问题

那缺点也很明显 , 它的实时性不够 , 如果出现一些突发事件 , 导致一些本来不是热词的内容变成了热词了

比如 : 春晚这个关键词 , 如果定期生成的话 , 假如周期是一个月 , 那年都过完了 , 春晚这个热搜才被统计出来

3.2 实时生成

实时生成的策略是 :

  • 如果在 Redis 中查询到数据 , 就直接返回数据
  • 如果在 Redis 中查询不到数据 , 那就把查询到的结果也写入到 Redis 中

但是这样不停地写 Redis , 就会使 Redis 的内存占用越来越多 , 从而逐渐的达到内存上限

此时如果继续插入数据 , 就会出现一些问题 , 为了解决上述情况 , Redis 就引入了一些内存淘汰策略

  1. 先进先出 (FIFO - First In First Out) : 将缓存中存在时间最久的数据 (最先来的数据) 淘汰掉
  2. 淘汰最久未使用的 (LRU - Least Recently Used) : 记录每个 key 的最近访问时间 , 将最近访问时间最老的 key 淘汰掉
  3. 淘汰访问次数最少的 (LFU - Least Frequently Used) : 记录每个 key 最近一段时间的访问次数 , 把访问次数最少的淘汰掉
  4. 随机淘汰 (Random) : 从所有的 key 中随机抽取某个 key 然后淘汰掉

在 Redis 中有一个配置项 , 就可以设置 Redis 采取哪种内存淘汰策略

  1. LRU 策略 (最近最少使用)
    1. volatile-lru : 从设置了过期时间的 key 中使用 LRU 算法进行淘汰
    2. allkeys-lru : 从所有 key 中使用 LRU 算法进行淘汰
  2. LFU 策略 (最近访问最少)
    1. volatile-lfu : 在已经过期的 key 中使用 LFU 算法进行淘汰
    2. allkeys-lfu : 从所有 key 中使用 LFU 算法进行淘汰
  3. Random (随机淘汰)
    1. volatile-random : 从设置了过期时间的 key 中随机淘汰数据
    2. allkeys-random : 从所有 key 中随机淘汰数据
  4. FIFO (先进先出)
    1. volatile-ttl : 根据过期时间进行淘汰 , 越早过期的越先被淘汰 (相当于 FIFO , 只不过是针对过期的 key)
  5. noeviction 默认策略 : 当内存不⾜以容纳新写⼊数据时 , 新写入操作会报错 .

经过一段时间的动态平衡 , Redis 中的 key 就都逐渐成了热点数据了

四 . 缓存预热、缓存穿透、缓存雪崩、缓存击穿

4.1 缓存预热

我们之前了解过 , 缓存中的数据有两种更新策略

  1. 定期生成 : 这种情况一般不涉及缓存预热问题
  2. 实时生成 : 一般涉及到缓存预热文体

在 Redis 服务器首次接入之后 , Redis 服务器中是没有任何数据的 . 而实时生成的步骤是客户端先查询 Redis 的数据 , 如果没查到就再查一次 MySQL , 然后将查询到的数据也写入到 Redis 中 .

这样的话 , 在服务器刚启动的时候 , 所有的请求都会访问 MySQL , 就会给 MySQL 造成不小压力 . 随着时间的推移 , Redis 上面积累的数据越来越多 , MySQL 的压力就会越来越小 .

所以我们就需要在服务器刚启动的时候进行缓存预热 , 避免服务器刚启动的时候导致 MySQL 压力过大 .

缓存预热的步骤是将定期生成和实时生成相结合 , 通过离线的方式用一些统计途径 , 先把热点数据找到一批然后导入到 Redis 中 . 此时导入的这些热点数据就能够减轻 MySQL 很大压力了 , 随着时间的推移 , 逐渐就可以使用新的热点数据淘汰掉旧的数据了 .

4.2 缓存穿透

缓存穿透指的是查询的某个 key , 他在 Redis 中查询不到 , 在 MySQL 中也查询不到 , 那这个 key 肯定也不会被更新到 Redis 中 .

那如果这样的数据存在很多并且还反复查询 , 一样也会给 MySQL 带来很大压力 .

一般来说 , 出现这样的情况主要有以下几个原因 :

  1. 业务设计不合理 : 比如缺少一些参数校验环节 , 导致非法的 key 也进行查询了
  2. 开发 / 运维误操作 : 不小心把部分数据删除掉了
  3. 黑客恶意攻击

我们通过改进业务 / 加强监控报警这些方法 , 虽然能够解决 , 不过是亡羊补牢 .

一般来说 , 主要采用的方案有以下几种 :

  1. 如果发现某个 key 在 Redis 和 MySQL 中都不存在 , 那将这个 key 写入到 Redis 中 , 然后将 value 设置成一个非法值 (比如 : “”)
  2. 引入布隆过滤器 : 在每次查询 Redis / MySQL 之前 , 都需要先判定一下 key 是否在布隆过滤器中是否存在 (我们会提前将所有的 key 插入到布隆过滤器中) .

布隆过滤器本质上是结合了 hash + bitmap 这两种结构 , 以较小的空间开销和较快的时间速度 , 实现针对 key 是否存在的判定

4.3 缓存雪崩

缓存雪崩指的是由于在短时间内 , Redis 上大规模的 key 失效 , 导致缓存命中率陡然下降 , 导致 MySQL 压力迅速上升 , 甚至宕机 .

产生这种情况主要有以下几种原因 :

  1. Redis 直接挂了 : Redis 宕机 / Redis 集群模式下大量节点宕机
  2. 之前短时间内设置了很多 key 给 Redis , 并且设置的过期时间是相同的 : 给 Redis 设置 key 作为缓存的时候 , 有的时候为了考虑缓存的时效性 , 就会设置过期时间 , 并且它是和 Redis 的内存淘汰机制是相配合使用的

那解决的原因一般如下 :

  1. 加强监控报警 , 加强 Redis 集群可用性
  2. 不给 key 设置过期时间 , 或者设置过期时间添加随机因子 (防止同一时刻过期)

4.4 缓存击穿

缓存击穿的英文全称指的是 Cache breakdown , 其中 breakdown 更适合翻译成瘫痪

所以缓存击穿我们就可以理解为缓存瘫痪 , 他是缓存雪崩的特殊情况 , 针对热点 key , 突然过期了 , 这样就导致了大量的请求直接访问到数据库上 , 甚至引起数据库宕机 .

它的解决方案主要有以下几点 :

  1. 基于统计的方式发现一些非常热点的 key , 并且设置永不过期 : 这需要服务器结构做出较大的调整 , 专门设置一个方法来去统计
  2. 进行必要的服务降级 : 例如访问数据库的时候使用分布式锁 , 限制服务器同时请求数据库的并发数

服务降级指的就是本身我们服务器的功能有 10 个 , 但是在一些特定情况下适当的关闭一些不重要的功能 , 只保留一些核心的功能 (超级省电模式 , 只保留了电话、短信、相机等核心功能)


文章到这里就结束喽 , 不知道你有没有被缓存预热、缓存穿透、缓存雪崩、缓存击穿绕蒙 , 如果对你有帮助的话 , 还请一键三连 , 你的鼓励是对我最大的认可~
在这里插入图片描述

这篇关于Redis 缓存深度解析:穿透、击穿、雪崩与预热的全面解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145200

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象

OWASP十大安全漏洞解析

OWASP(开放式Web应用程序安全项目)发布的“十大安全漏洞”列表是Web应用程序安全领域的权威指南,它总结了Web应用程序中最常见、最危险的安全隐患。以下是对OWASP十大安全漏洞的详细解析: 1. 注入漏洞(Injection) 描述:攻击者通过在应用程序的输入数据中插入恶意代码,从而控制应用程序的行为。常见的注入类型包括SQL注入、OS命令注入、LDAP注入等。 影响:可能导致数据泄

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动