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): 动态主机配置协议,主要需要配置的参数有…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...