Redis 击穿、穿透与雪崩:深度解析与应对策略
在使用 Redis 作为缓存的系统架构中,缓存击穿、穿透和雪崩是三个常见且可能对系统性能产生严重影响的问题。深入理解这些问题并掌握有效的应对策略对于构建稳定、高效的系统至关重要。
一、缓存击穿
(一)问题描述
缓存击穿是指一个热点 key 在缓存中突然过期,而此时大量并发请求同时访问这个 key,由于缓存中不存在该数据,这些请求会直接穿透到数据库查询数据,并且在查询到数据后重新将数据写入缓存。在高并发场景下,数据库可能瞬间承受巨大的压力,甚至导致数据库服务不可用。
例如,在一个电商系统中,某个热门商品的详情信息被缓存了。当缓存过期时,恰好有大量用户同时点击查看该商品详情,这些请求就会同时涌向数据库获取商品数据,可能使数据库负载急剧上升。
(二)处理方法
- 设置热点数据永不过期:对于一些极端热点且更新频率极低的数据,可以设置其在缓存中永不过期。这样可以避免因缓存过期导致的击穿问题,但需要注意数据一致性的维护,当数据有更新时,要及时更新缓存中的数据。
- 使用互斥锁:当缓存中不存在热点 key 时,在访问数据库之前先获取一个互斥锁。只有获取到锁的线程才能去数据库查询数据并更新缓存,其他线程则等待。在获取锁的线程完成数据库查询并更新缓存后,释放锁,其他线程再从缓存中获取数据。示例代码如下(以 Java 语言使用 Redis 的 Jedis 客户端为例):
java
public String getValue(String key) {String value = redis.get(key);if (value == null) {// 获取锁if (redis.setnx(key + "_lock", "locked") == 1) {try {// 再次检查缓存,防止其他线程已经更新缓存value = redis.get(key);if (value == null) {// 从数据库查询数据value = db.query(key);// 将数据写入缓存redis.set(key, value);}} finally {// 释放锁redis.del(key + "_lock");}} else {// 等待一段时间后重试Thread.sleep(100);return getValue(key);}}return value;
}
这种方式可以有效控制并发访问数据库的数量,但会增加系统的响应时间,因为线程需要等待锁的获取。
二、缓存穿透
(一)问题描述
缓存穿透是指查询一个根本不存在的数据,缓存和数据库都不会命中,这样的请求每次都会穿透缓存到达数据库,导致数据库压力增大。如果攻击者恶意构造大量这样的请求,可能会使数据库服务崩溃。
例如,在一个用户系统中,攻击者故意发送大量不存在的用户 ID 查询请求,这些请求都会直接访问数据库,数据库不断进行无效查询操作,浪费大量资源。
(二)处理方法
- 缓存空对象:当查询数据库未找到数据时,将空对象缓存起来,并设置一个较短的过期时间。这样后续相同的查询请求就可以直接从缓存中获取空结果,避免再次查询数据库。示例代码如下:
java
public String getValue(String key) {String value = redis.get(key);if (value == null) {// 从数据库查询数据value = db.query(key);if (value == null) {// 将空对象缓存起来,设置过期时间为 60 秒redis.setex(key, 60, "");} else {// 将数据写入缓存redis.set(key, value);}}return value;
}
但这种方法可能会导致缓存中存储大量无用的空对象数据,占用缓存空间,并且如果数据库中数据后续有更新,可能会出现数据不一致的情况。
2. 布隆过滤器:在访问缓存之前,先使用布隆过滤器判断请求的数据是否可能存在于数据库中。布隆过滤器是一种基于位图的数据结构,可以高效地判断一个元素是否在集合中,但存在一定的误判率(误判为存在但实际不存在)。如果布隆过滤器判断数据可能不存在,那么直接返回空结果,不再查询缓存和数据库;如果判断数据可能存在,则继续正常的缓存查询流程。示例代码如下(以 Guava 库中的布隆过滤器为例):
java
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;public class BloomFilterExample {private static final int EXPECTED_INSERTIONS = 1000000;private static final double FPP = 0.01;private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), EXPECTED_INSERTIONS, FPP);static {// 初始化布隆过滤器,将数据库中已有的数据对应的 key 加入布隆过滤器List<Integer> existingKeys = db.getAllKeys();for (Integer key : existingKeys) {bloomFilter.put(key);}}public String getValue(String key) {int keyInt = Integer.parseInt(key);if (!bloomFilter.mightContain(keyInt)) {return "";}String value = redis.get(key);if (value == null) {value = db.query(key);if (value == null) {redis.setex(key, 60, "");} else {redis.set(key, value);}}return value;}
}
使用布隆过滤器可以有效减少缓存穿透的发生,但需要合理设置误判率和预估数据量,并且在数据库数据有新增或删除时,需要及时更新布隆过滤器。
三、缓存雪崩
(一)问题描述
缓存雪崩是指在短时间内,大量缓存中的 key 同时过期或者 Redis 服务突然不可用,导致大量请求直接访问数据库,数据库压力瞬间剧增,可能导致数据库服务崩溃,进而影响整个系统的正常运行。
例如,在一个社交系统中,很多用户的动态数据都被缓存了,并且设置了相同的过期时间。当这些缓存同时过期时,大量用户的请求就会同时涌向数据库获取动态数据,使数据库不堪重负。
(二)处理方法
- 设置缓存过期时间随机化:将缓存的过期时间设置为一个随机值,避免大量缓存同时过期。例如,可以在原本设置的过期时间基础上,加上一个随机的时间偏移量,使不同 key 的过期时间分布在一个时间段内。示例代码如下:
java
public void setValue(String key, String value) {// 原本设置的过期时间为 600 秒int baseExpireSeconds = 600;// 随机生成 0 - 300 秒的偏移量int randomOffset = new Random().nextInt(300);// 最终的过期时间int expireSeconds = baseExpireSeconds + randomOffset;redis.setex(key, expireSeconds, value);
}
- 使用缓存预热:在系统启动或缓存服务重启时,提前将一些热点数据加载到缓存中,避免在用户请求高峰时因缓存未命中而导致大量请求穿透到数据库。可以在系统启动时编写一个数据加载脚本,从数据库中查询热点数据并写入缓存。
- 搭建高可用的 Redis 集群:使用 Redis 集群可以提高 Redis 的可用性和容错性。当部分节点出现故障时,集群中的其他节点可以继续提供服务,减少因 Redis 服务不可用导致的雪崩影响。常见的 Redis 集群方案有主从复制、哨兵模式和 Redis Cluster 等。例如,在主从复制模式下,主节点负责写操作,从节点负责读操作,从节点会定期从主节点同步数据。当主节点故障时,可以手动或自动将从节点提升为主节点,继续提供服务。
- 限流与降级:在系统中引入限流和降级机制,当发现缓存雪崩发生且数据库压力过大时,对部分非核心业务的请求进行限流,只允许一定数量的请求通过,或者直接对这些非核心业务进行降级处理,返回默认数据或提示信息,以保护数据库和整个系统的稳定性。例如,可以使用令牌桶算法或漏桶算法进行限流,在代码中根据业务的重要性设置不同的限流阈值和降级策略。
综上所述,缓存击穿、穿透和雪崩是 Redis 缓存使用过程中需要重点关注的问题。通过合理设置缓存过期时间、使用互斥锁、缓存空对象、布隆过滤器、缓存预热、搭建高可用集群以及限流降级等多种技术手段,可以有效地预防和应对这些问题,提高系统的性能、稳定性和可靠性,为用户提供更好的服务体验。在实际的系统开发和运维中,需要根据系统的业务特点、数据规模和并发量等因素,综合运用这些策略,不断优化系统架构和缓存策略。
相关文章:
Redis 击穿、穿透与雪崩:深度解析与应对策略
在使用 Redis 作为缓存的系统架构中,缓存击穿、穿透和雪崩是三个常见且可能对系统性能产生严重影响的问题。深入理解这些问题并掌握有效的应对策略对于构建稳定、高效的系统至关重要。 一、缓存击穿 (一)问题描述 缓存击穿是指一个热点 key…...
8086处理器的寻址方式
概念 在计算机系统中,处理器操作和处理的是数值,那么,必定涉及数值从哪里来,处理后送到哪里去,这称为寻址方式(Addressing Mode)。 简单地说,寻址方式就是如何找到要操作的数据,以及如何找到存…...
Mask实现裁剪的原理浅析
简单来说,就是Mask会设置继承了MaskableGraphic的组件的Shader属性,进行特定的模板测试 一张普通的Image,当不挂Mask组件时,其默认Shader的模板缓存属性是这样的 当挂载上Mask时,会改变 Stencil ID变成了1ÿ…...
每隔一秒单片机向电脑发送一个16进制递增数据
SCON0x50 SM00 SM11(工作方式为方式一) REN1允许单片机从电脑接收数据 TB8 RB8 SM2是方式2和方式3直接配置为0 TI为发送中断请求标志位 由硬件配置为1 必须由 软件复位为0,RI为接收中断请求标志位,同理TI UART.c #include &l…...
逆向攻防世界CTF系列56-easy_Maze
逆向攻防世界CTF系列56-easy_Maze 64位无壳,看题目就知道是迷宫问题了 int __fastcall main(int argc, const char **argv, const char **envp){__int64 v3; // raxint v5[7][7]; // [rsp0h] [rbp-270h] BYREFint v6[104]; // [rspD0h] [rbp-1A0h] BYREFv6[52] 1…...
【Linux网络编程】应用层:HTTP协议 | URL | 简单实现一个HTTP服务器 | 永久重定向与临时重定向
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站 🌈个人主页: 南桥几晴秋 🌈C专栏: 南桥谈C 🌈C语言专栏: C语言学习系…...
电压调整电路汇总
目录: 一、LDO 1、LM1117 2、NCV33275 3、TLE42764 4、TPS7B67xx-Q1 5、总结 二、DCDC转换器 1、LM2576与LM2596 2、MC34063 一、LDO 1、LM1117 LM1117 是一款在 800mA 负载电流下具有 1.2V 压降的低压降稳压器。 LM1117 提供可调节电压版本,…...
day28 文件IO及进程线程基础
讨论光标共享情况 1.dup和dup2定义变量赋值都共享光标 2.使用两个描述符调用两次open函数打开同一个文件,不共享光标 #include <myhead.h>int main(int argc, const char *argv[]) {//1、描述符赋值给新的变量char buff[1024] "abcdefg";int ne…...
【Azure 架构师学习笔记】- Azure Function (1) --环境搭建和背景介绍
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Function 】系列。 前言 随着无服务计算的兴起和大数据环境中的数据集成需求, 需要使用某些轻量级的服务,来实现一些简单操作。因此Azure Function就成了微软云上的一个必不可少的组成部分。 …...
前端文件下载
这里写自定义目录标题 前端文件下载方法使用a标签使用iframe标签二进制流 前端文件下载方法 使用a标签 /*** 文件下载方法 使用a标签* 存在浏览器下载时,太快的话,会取消上次的下载请求* param {*} href* param {*} filename*/ export function downlo…...
前端成长之路:HTML(3)
在HTML中,有列表标签。列表最大的特点是整齐、简洁、有序,用列表进行布局会更加自由方便。根据使用的情景不同,可以将列表分为三大类:无序列表、有序列表和自定义列表。 无序列表 在HTML中使用<ul>标签定义一个无序列表&a…...
无人机自动机库的功能与作用!
一、无人机自动机库的功能 智能停放与管理 无人机自动机库为无人机提供了一个安全、可靠的停放环境。通过先进的感知技术和安全防护措施,它能够实时监测周围环境,确保无人机免受恶劣天气或潜在风险的侵害。 无人机在机库内可以实现智能停放࿰…...
ubuntu 新建脚本shell并增加图标 双击应用实现python运行
1.使用nano创建shell脚本文件 需要在终端窗口中输入“nano”以打开文本编辑器。 nano 在创建脚本文件前,我们要了解脚本文件是如何运行的: 直接运行:直接在终端直接输入需要运行的脚本文件名称,系统或用缺省版本的shell运行脚…...
ANR 分析SOP
遇到ANR问题不要慌,大部分情况下可能是系统or测试手段问题,我们按照如下关键字排查定位 文章目录 1 是否是 heapdump 导致?1.1 dump开始1.2 dump结束 1 是否是 heapdump 导致? 使用 hprof: heap dump 关键词过滤,在d…...
COLA学习之环境搭建(三)
小伙伴们,你们好,我是老寇,上一节,我们学习了COLA代码规范,继续跟老寇学习COLA环境搭建 首先,打开GitHub,搜索 COLA 请给这个COLA项目点个Star,养成好习惯,然后Fork到自…...
CSS输入框动态伸缩动效
前言 下面我们将会做出如下图输入框样式,并且附上组件代码,有特殊需求的可以自行优化同理,下拉框的话只要把el-input标签修改掉即可 MyInput组件 <template><div class"my-input" click.stop"showInput !showInput…...
hbuilder 安卓app手机调试中基座如何设置
app端使用基座 手机在线预览功能 1.点击运行 2.点击运行到手机或者模拟器 3.制作自定义调试基座 4.先生成证书【可以看我上一篇文档写的有】,点击打包 5.打包出android自定义调试基座【android_debug.apk】,【就跟app打包一样需要等个几分钟】 6.点击运行到手…...
探索视觉与语言模型的可扩展性
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
sock_recvmsg函数
sock_recvmsg 是一个在 Linux 内核中用于处理接收网络数据的函数。它通常与套接字 (socket) 操作相关,特别是在网络协议栈中用于处理从网络中接收到的数据。这个函数是内核的一部分,提供了一种机制把接收到的数据从网络协议栈转移到用户空间,或者在内核内进一步处理。 以下是…...
HCIA笔记8--DHCP、Telnet协议
1. DHCP介绍 对于主机的网络进行手动配置,在小规模的网络中还是可以运作的,但大规模网络是无力应对的。因此就有了DHCP协议来自动管理主机网络的配置。 DHCP(Dynamic Host Configuration Protocol): 动态主机配置协议,主要需要配置的参数有…...
Scala的单例对象
在Scala中,单例对象是一种特殊的类,它只能有一个实例,并且这个实例在需要时会自动创建。单例对象在Scala中通过object关键字来定义,它类似于Java中的静态成员和方法,但更加灵活和强大。 定义单例对象 以下是定义一个…...
【笔记】分布式任务调度平台XXL-JOB
这篇笔记主要记录以下内容: (1)第一次启动xxl-job的过程 (2)模块、文件、数据库(表和字段)的作用 (3)极少的源码解读(XxlJobConfig) 有点像实…...
PDFMathTranslate,PDF多语言翻译,批量处理,学术论文,双语对照(WIN/MAC)
分享一个非常实用的PDF文档翻译项目——PDFMathTranslate。作为一个经常逛GitHub的开发者,我总喜欢翻看各种项目附带的论文,虽然大多时候是瞎研究,但却乐在其中。该项目能够完美保留公式、图表、目录和注释,对于需要阅读外文文献的…...
zerotier实现内网穿透(访问内网服务器)
moo 内网穿透工具 实用工具:zerotier 目录 内网穿透工具 Windows下zerotier安装 ubuntu系统下的zerotier安装 使用moon加速 Windows下zerotier安装 有了网络之后,会给你一个网络id,这个网络id是非常重要的,其它设备要加入…...
Formality:set_svf命令
相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 svf文件的全称是Setup Verification for Formality,即Design Compiler提供给Formality的设置验证文件,它的作用是为Formality的指导模式(Gui…...
IDEA报错:无效的源发行版、无效的目标发行版
1. 无效的源发行版 创建项目的时候,会遇见这个报错,原因就是编译的JDK版本与发布版本不一致。 解决方法: 1.1. 找到问题所在地 英文:File -> Project Structure ->Project Settings 中文:文件->项目结构 …...
#渗透测试#红蓝对抗#SRC漏洞挖掘# Yakit插件使用及编写01
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
Scala中求斐波那契数列的第n项
求斐波那契数列的第n项 问题:求 斐波那契数列的第n项 记: 0 1 1 2 3 5 8 13 21 34 55 ... 从第3项开始 f(n) f(n-1) f(n-2) 1.基本情况(直接能求的):f(0) 0,f(1) 1 2.递归情况(大事化小,自己…...
ORACLE修改序列值为表内某字段(主键)最大值
ORACLE修改序列值为表内某字段(主键)最大值 想修改序列值,网上基本的都是自己看要加到多少,然后要么调步长,要么删了重建。 想直接用declare使用标量然后调,但是逻辑里面不能有DDL语句。 不过最后解决了 直…...
前端html,vue使用第三方地图详细教程,以百度地图为例,实现地图标注,导航,定位,路线规划,坐标转换
目录 示例: 准备: ?编辑 开始: 1、新建页面,在script标签中引入百度地图的api数据,把自己在控制台创建的应用的ak替换上去 2、创建一个dom对象,设置宽高 3、在js中初始化地图 进阶: 1…...
广州易网网站建设/站长统计ios
(注:环境Mac OS X Lion 10.7.3 Xcode 4.2.1 iOS SDK 5.0.)一、新建iOS Application工程,选择Single View Application,不要选中Use Storyboard.假设指定的是product name和class prefix都是one,则完成后自动生成代码视图如下图:…...
长沙网站建设哪家靠谱/郑州见效果付费优化公司
String.prototype.charAt()str.charAt(index)返回字符串中指定位置的字符。字符串中的字符从左向右索引,第一个字符的索引值为 0,最后一个字符(假设该字符位于字符串 stringName 中)的索引值为 stringName.length - 1。如果指定的 index 值超出了该范围&…...
商城建站服务/东莞seo优化
下面由sublime教程栏目给大家介绍sublime自动修复eslint报错的方法,希望对需要的朋友有所帮助!问题描述PyQt 环境正常,可以使用 Windows 的 虚拟 DOS 正常运行,但在 Sublime Text 2 下使用 Ctrl B运行后,界面不显示&a…...
网站开发与维护是干什么的/小视频网站哪个可以推广
linux下mysql 启动问题刚开始学mysql时都是用redhat自带的。启动是什么 /rc.d/init.d/ start这很简单,但是后来越学越多,系统自带的mysql,有的是版本太低,有的是与自己想要装的web服务需要的低版本的mysql后来自己学着以tar的方式…...
扁平化配色方案网站/在线域名查询网站
给定一个字符串s,将s分割成一些子串,使每个子串都是回文串。 返回s所有可能的回文串分割方案。 样例 给出 s "aab",返回 [ [“aa”, “b”], [“a”, “a”, “b”] ] 分析:采用深度优先搜索即可,这种回文串…...
域名备案要先做网站的吗/合肥做网站推广
笔者原以为是个挺容易个事儿, 毕竟是微软自家的产品安装在自家的操作系统上, 没想到还是让我费了半天劲. 写在这里吧, 方便其他的朋友. 具体步骤 1. 准备好Windows Server 2012 R2 RTM的一台虚拟机, 准备SharePoint 2013 RTM的安装包, 和SP1的安装包. 2. 制作slipstream安装文…...