Redis缓存雪崩、穿透、击穿原因分析和解决方案,附Redis管道使用技巧

news2024/9/24 19:20:29

先给大家附上其他几篇文章,感兴趣的自行开车导航

Redis过期策略和持久化机制全面揭秘,教你如何合理配置

【深入浅出Redis 一】从版本特性到数据类型到线程模型,带你了解Redis的核心特性和应用场景!

一次redis OOM问题分析解决,rdbtools安装分析redis内存

Redis管道及缓存问题解析

一、什么是Redis管道

Redis管道(pipeline)是一种在网络层面上实现的批量操作机制,它可以将多个命令一次性发送给Redis服务器,而不需要等待每个命令的响应。这样可以减少客户端和服务器之间的网络通信次数,提高命令执行效率。

Redis管道的原理是基于TCP协议的请求/响应模型,即客户端发送一个请求后,必须等待服务器的响应才能发送下一个请求。如果客户端有多个请求要发送,那么就会产生多次网络往返延迟(RTT),影响性能。

而通过管道技术,客户端可以将多个请求打包成一个数据包发送给服务器,服务器也会将多个响应打包成一个数据包返回给客户端,从而减少网络延迟。并且有些场景也避免了事务问题,比如设置key和设置时间

二、如何使用Redis管道

使用Redis管道非常简单,只需要在发送命令之前调用pipeline()方法,创建一个管道对象,然后将命令添加到管道对象中,最后调用execute()方法执行所有命令并返回结果列表。下面是一个java示例:

Jedis jedis = new Jedis("localhost"); 
Pipeline p = jedis.pipelined(); 
p.set("foo","bar"); p.get("foo"); 
List<Object> results = p.syncAndReturnAll();

需要注意的是,使用管道并不保证原子性,即如果有其他客户端在管道执行过程中修改了数据,那么可能会影响管道中的命令结果。如果需要保证原子性,可以使用事务(transaction)或Lua脚本。

什么是缓存雪崩、缓存穿透、缓存击穿

Redis作为目前使用最广泛的缓存,相信大家都不陌生。但是使用缓存并没有这么简单,还要考虑缓存雪崩、缓存击穿、缓存穿透的问题,这些问题都可能导致大量请求直接打在数据库上,造成数据库压力过大甚至宕机。

那么这些问题分别是什么意思呢?

缓存雪崩

缓存雪崩是指当某一个时刻出现大规模的缓存失效的情况(比如Redis宕机或者大量key同时过期),导致大量请求直接打在数据库上,造成数据库压力巨大甚至宕机。这就像一场雪崩一样,一旦发生就很难控制。

缓存穿透

缓存穿透是指当用户请求的数据在缓存和数据库中都不存在时(比如请求一个不存在的id),导致每次请求都会到数据库中查询,从而给数据库造成压力。这就像穿透了缓存一样,直接访问数据库。

缓存击穿

缓存击穿是指当一个热点key在缓存中过期时,同时有大量请求过来查询这个key,导致大量请求直接打在数据库上,造成数据库压力剧增。这就像击穿了缓存一样,直接访问数据库。

四、如何解决缓存问题

说到底就是最终落到数据库了,如果有大量请求数据库就会被群殴致死,针对上面三种缓存问题,我们可以采用不同的解决方案,下面分别介绍。

解决缓存雪崩

解决缓存雪崩的关键在于避免大规模的key同时失效,有几种方法:

  • 设置不同的过期时间。避免缓存设置相同的过期时间,可以在设置过期时间时增加一个随机值,使得过期时间均匀分布。(推荐)
  • 数据预热。对于即将到来的大流量请求,可以提前将数据加载到缓存中,并设置不同的过期时间。
  • 保证Redis服务高可用。为了防止Redis宕机导致缓存雪崩的问题,可以搭建Redis集群或哨兵模式,提高Redis的容灾性。
  • 使用熔断机制。当流量到达一定的阈值时,可以直接返回“系统拥挤”之类的提示,防止过多的请求打在数据库上。
  • 提高数据库的容灾能力。可以使用分库分表、读写分离、负载均衡等策略,提高数据库的承载能力和稳定性。

解决缓存穿透

解决缓存穿透的关键在于避免查询不存在的数据,有以下几种方法:

  • 参数校验。对用户请求的参数进行校验,对于明显错误或非法的参数,直接拦截返回。
  • 缓存空值。对于查询为空的数据,也可以将其缓存在Redis中,并设置一个较短的过期时间(比如30秒),这样可以防止短时间内大量重复查询。
  • 使用布隆过滤器。布隆过滤器是一种数据结构,利用极小的内存,可以判断大量数据“一定不存在或者可能存在”。对于缓存穿透,我们可以将所有可能存在的key哈希到一个足够大的布隆过滤器中,用户请求时先判断key是否在布隆过滤器中,如果不在就直接返回。(推荐)

解决缓存击穿

解决缓存击穿的关键在于避免热点key失效时造成大量请求打在数据库上,有以下几种方法:

  • 设置热点数据永不过期。对于某些需要频繁访问的数据,可以将其设置为永不过期的key,当然这种方式比较粗暴,对于某些业务场景是不适合的。
  • 定时更新。对于某些有固定过期时间的热点数据,可以在其快要过期前通过定时任务去更新它,并重新设置过期时间。
  • 使用互斥锁。当缓存失效时,只有拿到锁的请求才能去查询数据库并更新缓存,其他请求则等待或重试。这样可以降低同时打在数据库上的请求数量。

缓存和数据库双写一致性问题

在使用Redis作为缓存时,我们通常需要在数据发生变化时,同时更新缓存和数据库,以保证数据的一致性。但是由于网络延迟或者其他原因,可能会导致缓存和数据库的数据不一致。

例如,如果先更新缓存再更新数据库,那么如果缓存更新成功而数据库更新失败,就会导致缓存中的数据是脏数据。

如果先更新数据库再更新缓存,那么如果数据库更新成功而缓存更新失败,就会导致缓存中的数据是旧数据。

那么如何解决这个问题呢?

解决方案

针对这个问题,有几种解决方案:

  • 先删除缓存再更新数据库。这种方式可以保证数据库中的数据是最新的,但是可能会导致短时间内的缓存不命中,增加数据库压力。为了避免这个问题,可以在删除缓存后延迟一段时间(比如1秒)再更新数据库,这样可以减少其他请求查询到空缓存的概率。
  • 先更新数据库再删除缓存。这种方式可以保证缓存中的数据是最新的,但是可能会导致删除缓存失败,导致缓存过期。为了避免这个问题,可以在删除缓存后延迟一段时间(比如1秒)再次删除缓存,减少其他请求查询到过期缓存的概率。
  • 使用消息队列。将更新操作放入消息队列中,保证顺序执行,并且可以重试失败的操作。这样可以保证最终一致性,但是可能会增加系统复杂度和延迟。
  • 使用分布式锁。在更新操作前获取一个分布式锁,保证同一时刻只有一个请求能够更新数据,并且在更新完成后释放锁。这样可以保证强一致性,但是可能会降低并发性能和可用性

开发过程中看起来我们都是先处理数据再删缓存的

其他问题

  • 缓存穿透、击穿、雪崩的监控和预警。为了及时发现和处理缓存问题,需要对Redis的性能和状态进行监控和预警,比如监控Redis的QPS、响应时间、内存使用率、命中率等指标,当发现异常时及时报警并处理。
  • 缓存的合理使用。不是所有的数据都适合放入缓存中,需要根据数据的访问频率、更新频率、大小等因素进行权衡。一般来说,适合放入缓存的数据应该满足以下条件:
    • 访问频率高,更新频率低。这样可以提高缓存命中率,减少数据库压力。
    • 数据量小,计算量大。这样可以减少网络传输开销,提高计算效率。
    • 数据一致性要求不高。这样可以容忍缓存和数据库之间的短暂不一致。

业务场景举例

下面举几个使用Redis作为缓存的业务场景:

  • 商品详情页。商品详情页是电商网站中最常访问的页面之一,每个商品都有一个唯一的id作为key,商品的基本信息、库存、评价等作为value。这些数据一般不会频繁变化,但是访问量很大,所以适合放入Redis中作为缓存。当用户访问某个商品详情页时,先从Redis中查询,如果命中则直接返回,如果不命中则从数据库中查询,并将结果放入Redis中,并设置一个过期时间(比如1小时)。当商品信息发生变化时(比如库存变化),需要同时更新数据库和缓存。
  • 热门排行榜。热门排行榜是展示某个维度下最受欢迎的内容的列表,比如电影排行榜、音乐排行榜、新闻排行榜等。这些数据一般会根据某个指标(比如评分、播放量、点击量等)进行排序,并定期更新。这些数据适合放入Redis中作为缓存,因为它们访问量大,计算量大,数据量小。可以使用Redis的有序集合(sorted set)来实现排行榜功能,每个元素对应一个内容id,分数对应一个指标值。当用户访问某个排行榜时,先从Redis中查询,如果命中则直接返回,如果不命中则从数据库或其他服务中查询,并将结果放入Redis中,并设置一个过期时间(比如10分钟)。当内容的指标值发生变化时(比如评分变化),需要同时更新数据库和缓存。
  • 验证码。验证码是一种用于防止机器人或恶意用户的一种安全机制,一般在用户注册、登录、下单等场景中使用。验证码一般有一个有效期(比如5分钟),并且只能使用一次。这些数据适合放入Redis中作为缓存,因为它们访问频率高,更新频率高,数据量小,数据一致性要求不高。可以使用Redis的字符串(string)来实现验证码功能,每个key对应一个用户id或手机号,value对应一个验证码。当用户请求发送验证码时,生成一个随机的验证码,并将其存入Redis中,并设置一个过期时间(比如5分钟)。当用户输入验证码时,先从Redis中查询,如果命中则验证是否正确,如果不命中则提示验证码已过期或不存在。当验证码验证成功或失败时,需要删除Redis中的key。

今天就介绍到这里,感谢大家

感兴趣的自行开车导航

Redis过期策略和持久化机制全面揭秘,教你如何合理配置

【深入浅出Redis 一】从版本特性到数据类型到线程模型,带你了解Redis的核心特性和应用场景!

一次redis OOM问题分析解决,rdbtools安装分析redis内存

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

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

相关文章

PyTorch深度学习——Anaconda和PyTorch安装

一、Anaconda安装 前言 安装anaconda后主要有一下3点好处&#xff1a; 1.包含环境管理器conda。 2.大量安装基于python的工具包。 3.可以创建使用和管理不同的python版本。 附上百度百科的解释&#xff1a; 下载步骤&#xff1a; 1.官网下载anaconda 2.双击之后安装即可 …

【Linux】进程间通信——管道与共享内存

文章目录 前言 1、三个问题1-1、什么是通信&#xff1f;1-2、为什么要有通信1-3、怎么进行通信&#xff1f;1-4、进程间通信分类 2、管道2-1、匿名管道2-1-1、理解通信本质问题2-1-2、进一步理解管道2-1-3、代码实现pipe函数 2-1-4、读写特征2-1-5、管道的特点&#xff08;重点…

MQTT springboot + idea

参考链接&#xff1a;&#xff08;第一个是理论 第二个是代码 我是直接cv的 我就不贴代码了&#xff09; MQTT协议基本流程、原理_mqtt协议工作原理_Nimrod__的博客-CSDN博客 SpringBoot整合MQTT_springboot mqtt_N_P_E的博客-CSDN博客 EMQX 入门教程③——默认端口、端口策…

10.Java 基本数据类型与包装类之间的转换

Java 的包装类便是一种特殊的引用数据类型&#xff0c;因为其是与基本数据类型一一对应的 1.装箱和拆箱 装箱指的是将基本数据类型转为包装类&#xff1b;拆箱指的是将包装类转为基本数据类型 1.1 int 与 Integer 之间的转换 int → Integer int i 13; Integer integer I…

基于JSP+servlet+JDBC开发的人物管理系统

文章目录 技术说明【效果图】源码 技术说明 后端&#xff1a;JspServletJDBC 前端&#xff1a;BootStrap技术 数据库&#xff1a;Mysql 其他&#xff1a;ckeditor富文本编辑器、FileUpload组件上传图片、MD5加密技术 功能&#xff1a;人物的增删改查 【效果图】 源码 https:…

mysql、redis 、RabbitMQ只能本机访问,怎么改?

如果只能本机访问&#xff0c;怎么改? 一、mysql - 改my.ini 刷脚本 bind-address0.0.0.0 然后重启一下mysql服务 任务管理器-关掉mysql 搜索 计算机管理-重启mysql服务 然后 打开查询&#xff0c;并选择mysql数据&#xff0c;输入这个sql语句&#xff0c;点击运行 sele…

小程序首页轮播图设计

效果图 微信小程序的数据详解 indicator-dots&#xff1a;是否显示面板指示点【默认false 】 indicator-color&#xff1a;指示点颜色【默认rgba(0, 0, 0, .3)】 indicator-active-color&#xff1a;当前选中的指示点颜色【默认#000000】 autoplay&#xff1a;是否自动切换…

总结928

在备考的过程中&#xff0c;我时不时会思考这个问题&#xff0c;我到底怎么样才能“一战成硕”&#xff0c;这个问题本质上就是如何达成目标的问题。 曾遇到这么一句话&#xff0c;90%的人没有目标&#xff0c;99.9%的人败在了目标上。当看到这句话&#xff0c;我还以为是我的…

WEB:upload1

题目 看到文件上传的一般思路是&#xff1a;构建一句话木马&#xff0c;利用bp修改包后缀名&#xff08;一般会限制上传文件类型&#xff09;&#xff0c;上传成功以后注意文件位置&#xff0c;利用菜刀或者是中国蚁剑进行连接&#xff0c; 然后获得flag 构建一句话木马 <…

什么是产品生命周期(PLM)管理系统?

引言 产品生命周期管理 (PLM) 涉及产品生命周期的每个阶段。从产品设计人员进行创造性构思&#xff0c;到物联网网络发送和接收宝贵的数据&#xff0c;再到接收客户真实且及时的反馈&#xff0c;整个产品生命周期中的每一条信息都至关重要&#xff0c;构成了完整的产品构成。 …

【雕爷学编程】Arduino动手做(02)---光敏电阻模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

联动规则组件-KOV场景梳理技术方案

一、背景&#xff1a; 多场景使用到kov类型组件&#xff0c;但是实现上不统一&#xff0c;各个场景的协议都比较定制&#xff0c;且开发的时候难度较大。所以将组件进行抽离 目标&#xff1a;支撑所有逻辑场景 什么是kov&#xff1f;如下图&#xff1a; 难点&#xff1a; 1、…

KVM-虚拟机【安装与基础使用】

目录 【1】kvm-01&#xff1a;安装-KVM管理工具 【2】创建新的虚拟机 【3】kvm常用管理命令 【4】console控制台登录 【5】修改虚拟机的密码 【6】KVM虚拟机的虚拟磁盘管理和快照管理 【7】将raw格式的磁盘挂载到宿主机 【8】磁盘的管理命令 【9】创建快照-内部快照 【…

java学习路程之篇七、知识点、赋值运算符、关系运算符、逻辑运算符、三元运算符、运算符优先级

文章目录 1、赋值运算符2、关系运算符3、逻辑运算符4、三元运算符5、运算符优先级 1、赋值运算符 2、关系运算符 3、逻辑运算符 4、三元运算符 5、运算符优先级

Elasticsearch和MySQL之间的数据同步问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章参考网上的课程&#xff0c;介绍Elasticsearch和MySQL之间的数据同步问题。 如果文章有什么需要改进的地方还请大佬不吝赐教&#x1f44f;&#x1f44f;。 小威在…

vue路由接口转发

目录 一、nginx的路由转发 二、vue路由转发 三、两者路由转发的区别 vue的路由和nginx的路由有许多相似之处&#xff0c;也有一些不同的地方。 两者都有接口转发的功能&#xff0c;但是具体转发的方式会有一些区别。 一、nginx的路由转发 nginx的路由是这样的&#xff1a;…

C# Modbus通信从入门到精通(3)——Modbus RTU(0x01功能码)

1、01(0x01)读线圈 使用该功能码能从远程地址中读取1到2000个线圈的状态,每个线圈的状态只能是0或者1,读取的线圈数据由主站读取时指定。 2、发送报文格式 更详细的格式如下: 从站地址+功能码+起始地址高位+起始地址低位+线圈数量高位+线圈数量低位+CRC,一共8个字节,其…

JS-变量

文章目录 1.变量概述1.1 什么是变量1.2 变量在内存中的存储 2.变量的使用2.1 声明变量2.2 赋值2.3 变量的初始化 3.变量语法扩展3.1 更新变量3.2 同时声明多个变量3.3 声明变量特殊情况 4.变量命名规范 1.变量概述 1.1 什么是变量 变量是用于存放数据的容器。 我们通过 变量名…

gulimall-性能监控-压力测试

性能监控与压力测试 前言一、性能监控1.1 jvm 内存模型1.2 jvisualvm 作用1.3 监控指标 二、压力测试2.1 概念2.2 性能指标2.3 JMeter 压测工具 前言 本文继续记录B站谷粒商城项目视频 P141-150 的内容&#xff0c;做到知识点的梳理和总结的作用。 一、性能监控 1.1 jvm 内存…

AcWing 106. 动态中位数—对顶堆

问题链接 AcWing 106. 动态中位数 问题描述 分析 推荐b站董晓算法视频讲解对顶堆 这道题应该用树状数组、平衡树也能解决&#xff0c;这里用对顶堆来做&#xff0c;对顶堆能够用维护第K位置的数&#xff0c;K是固定的&#xff0c;在这道题中&#xff0c;维护两个堆&#xff…