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

Redis:原理速成+项目实战——Redis实战4(解决Redis缓存穿透、雪崩、击穿)

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:Redis:原理+项目实战——Redis实战3(Redis缓存最佳实践(问题解析+高级实现))
📚订阅专栏:Redis速成
希望文章对你们有所帮助

上次已经讲解了企业级用Redis进行缓存更新的基础用法,并且进行了最佳实践。但是其实Redis在使用的过程中还是会出现各种问题:缓存穿透、缓存雪崩、缓存击穿。
其中缓存穿透比较好解决,在这里会进行解决。
缓存雪崩提一下解决方案就好了,真正的解决在Redis学到比较高级的时候,或者说在肝微服务架构的时候去具体解决。
缓存击穿的解决方法在这里也提一下,具体编码的解决在下一节进行

缓存穿透、雪崩、击穿及解决方案

  • 缓存穿透
    • 缓存穿透解决思路
    • 编码解决商铺查询的缓存穿透问题
  • 缓存雪崩及解决思路
  • 缓存击穿及解决思路
    • 解决思路——互斥锁
    • 解决思路——逻辑过期
    • 解决思路总结

缓存穿透

缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。过程即:
(1)客户端访问Redis,未命中
(2)接着访问数据库,未命中
这样的话,如果有人恶意多线程地访问不存在的内容,可能就把我们的系统弄垮了。

缓存穿透解决思路

常见的解决方案如下:

1、缓存空对象:
(1)客户端请求Redis,未命中
(2)接着访问数据库,未命中
(3)数据库将空值null缓存到Redis里
这样如果继续访问的话,就会访问Redis了,不会一直去对数据库造成攻击,尽管访问Redis以后返回的内容是NULL。
优点:实现简单,维护方便
缺点:额外内存消耗(每次进行不同的访问,都创建null,不过设置TTL可以解决);可能造成短期的不一致(设置为NULL之后,数据库真的新增了这个数据,不过设置TTL可以有效缓解这种情况的出现概率)

2、布隆过滤:
这其实是一种算法,它在客户端与Redis交互之间加了一个布隆过滤器
(1)用户请求布隆过滤器,不存在就直接拒绝
(2)存在的话就放行,让客户端去访问Redis,有就返回,没有就访问数据库
布隆过滤器存储的一系列的二进制位,这种二进制数是先对数据库数据进行某种哈希运算以后再转成二进制存储到布隆过滤器的,具体原理可以自行查询,这种算法实现方式决定了过滤器存在概率性:

如果过滤器返回不存在,那就是不存在;如果返回存在,那就不一定了。

优点:内存占用较少,没有多余key
缺点:实现复杂(不过Redis里面存在,可以简化开发);存在误判可能。

因为布隆过滤器存在误判,所以我们的开发过程中,会选择缓存空对象的方式来解决缓存穿透。

编码解决商铺查询的缓存穿透问题

1、我们需要在之前业务流程环节中增加缓存空对象的环节,即可解决,也就是根据id查询数据库的时候,判断商铺不存在之后,不再直接结束,而是将空值写入Redis。
2、那么我们之后的查询,可以在缓存中查询出null值,因此我们的查询就需要对查询出来的值进行判断,不是空值的话才能返回商铺信息到前端。
代码如下:

    @Overridepublic Result queryById(Long id) {String key = CACHE_SHOP_KEY + id;//从Redis中查询商铺缓存,存储对象可以用String或者Hash,这里用StringString shopJson = stringRedisTemplate.opsForValue().get(key);//判断是否存在if (StrUtil.isNotBlank(shopJson)) {//存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//判断命中的是否是nullif (shopJson != null){//返回错误信息return Result.fail("点评信息不存在");}//不存在,根据id查询数据库Shop shop = getById(id);//不存在,返回错误if (shop == null){//存一个null到Redis中//这种没用的信息,TTL没必要设置太长了,这里我设置成了2minstringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在");}//存在,写入RedisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);//返回return Result.ok(shop);}

当我们网页的id设置成0去查询店铺:
在这里插入图片描述
打开Redis,0号的商铺确实存入了Redis,且值为空:
在这里插入图片描述
到此,我们成功用代码解决了这个问题。

缓存雪崩及解决思路

缓存雪崩是指同一时段有大量的缓存key失效,或者Redis服务宕机,导致大量请求到达数据库,带来的巨大压力。
正常情况下,大量请求会到达Redis,少数请求到达数据库。而Redis一旦宕机,或者Redis中的大量key都因为TTL到期而失效了,这时候的很多请求都会指向数据库。
针对这个问题,我们可以提出一些解决方案:
1、给不同的key的TTL添加随机值,避免大量的key在同一个小时段内失效
2、利用Redis集群提高服务的可用性(Redis哨兵机制可以实现服务的监控,发现宕机的主Redis,就可以立刻将从Redis替代上去),这个内容相对比较高级,在之后讲。
3、给缓存业务添加降级限流策略(如果整个集群的Redis全部都宕机了,我们可以提前做容错处理,当这些Redis都失效的时候,我们要及时的拒绝请求,防止大量请求到达数据库)
4、给业务添加多级缓存

缓存击穿及解决思路

缓存击穿也叫作热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

我们可以这么理解,网站中有一些内容是非常的重要的,很可能在同一时段被多个用户给同时访问,也就是高并发访问,而这个被高并发访问的key失效了,这时候访问就会到达数据库,大量请求到达数据库是很危险的,很容易造成缓存雪崩。
即便数据库比较坚强,也有可能用户进行访问的内容是很复杂的,可能涉及到了多表查询,也可能其转换到Redis中进行存储的时候需要进行一系列的业务。当缓存重建业务复杂的时候,如此大的请求在那一瞬间给数据库带来的冲击是非常巨大的。

缓存击穿问题,有两种比较主流的解决方法:
1、互斥锁
2、逻辑过期

解决思路——互斥锁

互斥锁还是比较好理解的:
1、当第一个线程未命中缓存的时候,获取互斥锁,直到这个线程查询数据库完,并且重建了缓存数据并存入Redis,才能释放互斥锁;
2、后面的线程在缓存数据存入Redis的过程中,同样会发生查询Redis未命中的情况,那么这些线程无法获得互斥锁,只能进行休眠,休眠一段时间后再重试,直到锁被解开(Redis中已经有数据了)。
在这里插入图片描述
学过操作系统的同学应该知道,这个问题可能会出现的问题就是,线程之间很可能会出现相互等待的情况,当然操作系统中针对这些情况都还是有对应的一些解决方法的。

解决思路——逻辑过期

缓存击穿会出现的原因,其实无非就是TTL到期,Redis失效了,因此我们可以不给其设置TTL。但是我们该如何知道key过期了呢?我们要给这个key设置一个逻辑过期,类似:

KEYVALUE
wxj:user:1{name:“Jack”, age:21, expire:151467}

这里的expire不是TTL,而是我们添加到Redis之前设定的,用代码逻辑来进行维护。
那么这个key一旦存储到了Redis里面,没有任何干预的情况下是永不过期的。
也就是说有一个线程在查询缓存的时候,代码逻辑里发现逻辑时间过期了,我们也直接把旧数据返还给客户端,毕竟已经是高并发,一时的旧数据在很多时候也能接受,在我看来这是一种牺牲策略,客户端无须等待新数据到来,当然了,旧数据迟早要进行修改,但数据的更新操作完全可以交给其他线程,这样可以提高效率:
在这里插入图片描述

解决思路总结

解决方案优点缺点
互斥锁没有额外内存消耗;保持一致性;实现简单线程要等待,性能受影响;可能死锁
逻辑过期线程无需等待,性能较好不保证一致性;有额外内存消耗;实现复杂

其实我感觉两种思路完全是可以结合在一起的,当然具体还是要看业务的应用场景和需求。

在下面的文章将会进行缓存击穿的解决思路的编码实现。

相关文章:

Redis:原理速成+项目实战——Redis实战4(解决Redis缓存穿透、雪崩、击穿)

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:Redis:原理项目实战——Redis实战3(Redis缓存最佳实践(问题解析高级实现)&#x…...

后端开发——jdbc的学习(一)

上篇结束了Mysql数据库的基本使用,本篇开始对JDBC进行学习总结,开始先简单介绍jdbc的基本使用,以及简单的练习;后续会继续更新!以下代码可以直接复制到idea中运行,便于理解和练习。 JDBC的概念 JDBC&#…...

阿里云免费SSL证书时长只有3个月,应对方法来了

阿里云免费SSL证书签发有效期从12个月缩短至3个月:尊敬的用户,根据供应商变更要求,免费证书(默认证书)的签发有效期将由12个月缩短至3个月。 免费证书(升级证书)的有效期不会改变。 没错&#…...

Flutter 中使用 ICON

Flutter Icon URL : https://fonts.google.com/icons: 在Flutter中使用 Icon 步骤如下: 导入图标库 在Dart 文件中导入 material.dart 包,该包包含了 Flutter 的图标库。 import package:flutter/material.dart;使用图标组件 …...

百度编辑器常用设置

1、创建编辑器 UE.getEditor(editor, { initialFrameWidth:"100%" //初始化选项 }) 精简版 UE.getEditor(editor) 2、删除编辑器 UE.getEditor(editor).destroy(); 3、使编辑器获得焦点 UE.getEditor(editor).focus(); 4、获取编辑器内容 UE.getEditor(editor).getCo…...

Java ORM 框架 Mybatis详解

📖 内容 Mybatis 的前身就是 iBatis ,是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。本文以一个 Mybatis 完整示例为切入点,结合 Mybatis 底层源码分析,图文并茂的讲解 Mybatis 的核心工作机制。 …...

前端:html+css+js实现CSDN首页

提前说一下,只实现了部分片段哈!如下: 前端:htmlcssjs实现CSDN首页 1. 实现效果2. 需要了解的前端知识3. 固定定位的使用4. js 监听的使用4. 参考代码和运行结果 1. 实现效果 我的实现效果为: 原界面如下,网址为&…...

三种 SqlSession

三种 SqlSession ​SqlSession​ 是一个接口,并且里面包含了许多 CRUD 操作数据库等方法。 ​SqlSession​​ 它有三个实现类,分别是 SqlSessionManager​​ 、DefaultSqlSession​​ 和 SqlSessionTemplate​​,其中 DefaultSqlSession​​…...

Mybatis SQL构建器类 - 问题答案

问题 Java开发人员可能会碰到的最棘手的事情之一就是在Java代码中嵌入SQL语句。通常情况下,这是因为需要动态生成SQL语句 - 否则可以将其外部化到文件或存储过程中。正如你已经了解到的,MyBatis在其XML映射功能中有一个强大的解决方案来生成动态SQL。然…...

React 是什么?有什么特性?有哪些优势?

一、是什么 React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 这句话的意思是,React 是一个专注于构建用户界面的 JavaScript 库,它主要关注于解决 UI 层面的问题。它并不是一个全功能的框架,而是…...

瑞吉外卖项目详细总结

文章目录 瑞吉外卖1.技术栈2.项目文件架构3.业务功能模块(例子)3.1管理员登录接口层(Controller)3.2管理员登录实现层(ServiceImpl)3.3管理员登录服务层(Service)3.4管理员登录Mapper层 4.公共模块4.1 BaseContext(保存…...

Cytoscape 3.10安装包下载及安装教程

Cytoscape3.10下载链接:https://docs.qq.com/doc/DUkpuR0RVU0JVWkFP 1、选中下载好的安装包,右键选择解压到“Cytoscape 3.10”文件夹 2、双击打开“Cytoscape_3_10_0_windows_64bit.exe” 3.点击“Download”,请耐心等待“Java”完成 4、点击…...

data.TensorDataset解析

data.TensorDataset 是 PyTorch 中的一个类,用于创建一个包含多个张量的数据集。这个类的主要作用是将输入的张量组合成一个数据集,使得在训练过程中可以方便地进行数据加载和迭代。 具体来说,TensorDataset 接受一系列的张量作为输入参数&a…...

贝锐花生壳全新功能:浏览器一键远程访问SSHRDP远程桌面

为了满足特定场景的远程访问需求,如:远程群晖NAS设备、远程SQL Server数据库/MySQL数据库、3389远程桌面(RDP远程桌面)、远程SSH、我的世界游戏联机…… 贝锐花生壳推出了场景映射服务,不仅提供满足相应场景的网络带宽…...

2024 年度 AAAI Fellows 揭晓!清华大学朱军教授入选!

今日,国际人工智能领域最权威的学术组织 AAAI 揭晓 2024 年度 Fellows 评选结果,新增 12 位 Fellow。 其中,清华大学计算机系教授朱军因「在机器学习理论与实践方面做出的重大贡献」而成功入选,成为本年度入选的唯一华人学者&…...

Linux(openssl):用CA证书签名具有SAN的CSR

Linux(openssl):创建CA证书,并用其对CSR进行签名_生成ca证书签名请求文件csr-CSDN博客 提供了方法为CSR进行签名。 对于有SAN的CSR如何签名呢? 1.创建CA证书,与下面的帖子一样...

从零开始了解大数据(七):总结

系列文章目录 从零开始了解大数据(一):数据分析入门篇-CSDN博客 从零开始了解大数据(二):Hadoop篇-CSDN博客 从零开始了解大数据(三):HDFS分布式文件系统篇-CSDN博客 从零开始了解大数据(四):MapReduce篇-CSDN博客 从零开始了解大…...

增量预训练经验积累(3)

站在巨人的肩膀上才能走的更远~本文主要是针对《千亿参数开源大模型 BLOOM 背后的技术》进行学习和提取关键经验。 1、BLOOM与Megatron-DeepSpeed 1.1 BLOOM训练细节 BLOOM 的模型架构与 GPT3 非常相似,只是增加了一些改进,176B BLOOM 模型的训练于 2022 年 3 月至 7 月期…...

R语言【CoordinateCleaner】——cc_dupl():根据物种名称和坐标以及用户定义的附加列删除或标记重复的记录

Package CoordinateCleaner version 2.0-20 Parameters cc_dupl(x,lon "decimallongitude",lat "decimallatitude",species "species",additions NULL,value "clean",verbose TRUE ) 参数【x】:data.frame。包含地…...

Hadoop安装笔记1单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

将下发的ds_db01.sql数据库文件放置mysql中 12、编写Scala代码,使用Spark将MySQL的ds_db01库中表user_info的全量数据抽取到Hive的ods库中表user_info。字段名称、类型不变,同时添加静态分区,分区字段为etl_date,类型为String&am…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)

起因 为了实现在报销流程中&#xff0c;发票不能重用的限制&#xff0c;发票上传后&#xff0c;希望能读出发票号&#xff0c;并记录发票号已用&#xff0c;下次不再可用于报销。 基于上面的需求&#xff0c;研究了OCR 的方式和读PDF的方式&#xff0c;实际是可行的&#xff…...

计算机系统结构复习-名词解释2

1.定向&#xff1a;在某条指令产生计算结果之前&#xff0c;其他指令并不真正立即需要该计算结果&#xff0c;如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方&#xff0c;那么就可以避免停顿。 2.多级存储层次&#xff1a;由若干个采用不同实现技术的存储…...

window 显示驱动开发-如何查询视频处理功能(三)

​D3DDDICAPS_GETPROCAMPRANGE请求类型 UMD 返回指向 DXVADDI_VALUERANGE 结构的指针&#xff0c;该结构包含特定视频流上特定 ProcAmp 控件属性允许的值范围。 Direct3D 运行时在D3DDDIARG_GETCAPS的 pInfo 成员指向的变量中为特定视频流的 ProcAmp 控件属性指定DXVADDI_QUER…...