【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案
30分钟自学教程:Redis缓存击穿原理与解决方案
目标
- 理解缓存击穿的定义及核心原因。
- 掌握互斥锁、逻辑过期时间等预防技术。
- 能够通过代码实现高并发场景下的缓存保护。
- 学会熔断降级、热点探测等应急方案。
教程内容
0~2分钟:缓存击穿的定义与典型场景
- 定义:某个热点Key突然过期,导致瞬时高并发请求直接穿透缓存访问数据库,引发数据库压力激增。
- 与雪崩、穿透的区别:
- 雪崩:大量Key同时失效。
- 穿透:查询不存在的数据。
- 击穿:单个热点Key失效引发并发问题。
- 典型场景:
- 秒杀商品Key过期时,数万用户同时刷新页面。
- 新闻热点事件缓存到期,大量用户请求涌入。
2~5分钟:代码模拟击穿场景(Java示例)
// 未做并发控制的查询方法(模拟击穿问题)
public Product getProduct(String id) { String key = "product:" + id; Product product = redisTemplate.opsForValue().get(key); if (product == null) { // 假设此时有1000个并发请求同时进入此逻辑 product = productService.loadFromDB(id); redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS); } return product;
}
问题复现:
- 使用JMeter或Postman模拟100个并发请求访问该接口,观察数据库查询次数是否为1次(理想)或100次(实际击穿现象)。
5~12分钟:解决方案1——互斥锁(分布式锁)
- 核心思想:缓存失效时,仅允许一个线程重建数据,其他线程阻塞等待或重试。
- 代码实现(Redisson分布式锁):
public Product getProductWithLock(String id) { String key = "product:" + id; Product product = redisTemplate.opsForValue().get(key); if (product == null) { RLock lock = redissonClient.getLock("product_lock:" + id); try { if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 尝试获取锁,最多等待3秒 // 双重检查:其他线程可能已更新缓存 product = redisTemplate.opsForValue().get(key); if (product == null) { product = productService.loadFromDB(id); redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS); } } else { Thread.sleep(50); // 未获取锁,短暂等待后重试 return getProductWithLock(id); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } return product;
}
- 关键点:
- 锁粒度需精确到单个Key,避免全局锁性能问题。
- 必须设置锁超时时间,防止死锁。
12~20分钟:解决方案2——逻辑过期时间
- 原理:缓存永不过期,但业务层判断数据是否需更新(牺牲一定一致性)。
- 代码实现(封装逻辑过期时间):
// 数据包装类,包含逻辑过期时间
public class ProductWrapper { private Product product; private long expireTime; // 逻辑过期时间戳 // 构造方法、Getter/Setter
} public Product getProductWithLogicExpire(String id) { String key = "product:" + id; ProductWrapper wrapper = redisTemplate.opsForValue().get(key); if (wrapper == null) { // 首次加载数据 Product product = productService.loadFromDB(id); wrapper = new ProductWrapper(product, System.currentTimeMillis() + 3600 * 1000); redisTemplate.opsForValue().set(key, wrapper); return product; } else if (wrapper.getExpireTime() < System.currentTimeMillis()) { // 逻辑过期,异步更新缓存 CompletableFuture.runAsync(() -> { Product newProduct = productService.loadFromDB(id); redisTemplate.opsForValue().set(key, new ProductWrapper(newProduct, System.currentTimeMillis() + 3600 * 1000) ); }); } return wrapper.getProduct(); // 返回旧数据,保证可用性
}
- 适用场景:
- 读多写少的热点数据(如商品详情、新闻内容)。
- 允许短暂的数据不一致。
20~25分钟:解决方案3——热点Key探测与自动续期
- 原理:监控高频访问的Key,提前续期或标记为永久有效。
- 代码实现(简单监控逻辑):
// 热点Key监控器(伪代码)
public class HotKeyMonitor { private ConcurrentHashMap<String, AtomicInteger> accessCount = new ConcurrentHashMap<>(); @Scheduled(fixedRate = 60000) // 每分钟扫描一次 public void scanHotKeys() { accessCount.forEach((key, count) -> { if (count.get() > 1000) { // 访问量阈值 redisTemplate.expire(key, 2, TimeUnit.HOURS); // 自动续期 count.set(0); // 重置计数器 } }); } public void recordAccess(String key) { accessCount.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet(); }
} // 在查询方法中记录访问
public Product getProduct(String id) { String key = "product:" + id; hotKeyMonitor.recordAccess(key); // ...其他逻辑
}
25~28分钟:应急处理方案
- 熔断降级(Sentinel示例):
@SentinelResource(value = "getProduct", blockHandler = "handleBlock")
public Product getProduct(String id) { // 正常业务逻辑...
} // 熔断后返回默认数据
public Product handleBlock(String id, BlockException ex) { return new Product("默认商品", 0.0);
}
- 缓存预热:
// 定时预热即将过期的热点Key
@Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行一次
public void preloadHotData() { List<String> hotKeys = hotKeyMonitor.getHotKeys(); hotKeys.forEach(key -> { Long ttl = redisTemplate.getExpire(key); if (ttl != null && ttl < 60) { // 剩余时间小于60秒 String id = key.split(":")[1]; Product product = productService.loadFromDB(id); redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS); } });
}
28~30分钟:总结与优化方向
- 核心原则:分散并发压力、异步更新、监控兜底。
- 高级优化:
- 结合Redis Cluster实现高可用。
- 使用本地缓存(如Caffeine)作为一级缓存。
练习与拓展
练习
- 实现基于Redisson的分布式锁,并通过JMeter验证并发控制效果。
- 修改逻辑过期时间代码,支持动态调整过期阈值(如30分钟~2小时随机)。
推荐拓展
- 研究RedLock算法及其在分布式锁中的应用。
- 学习Redis的持久化机制(RDB/AOF)与数据恢复。
- 探索开源框架JetCache对缓存击穿的自动化处理方案。
相关文章:
【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案
30分钟自学教程:Redis缓存击穿原理与解决方案 目标 理解缓存击穿的定义及核心原因。掌握互斥锁、逻辑过期时间等预防技术。能够通过代码实现高并发场景下的缓存保护。学会熔断降级、热点探测等应急方案。 教程内容 0~2分钟:缓存击穿的定义与典型场景 …...
preloaded-classes裁剪
系统预加载了哪些class类?system/etc/preloaded-classes 修改源代码? frameworks\base\config\preloaded-classes 默认位置,如果改了不生效,可能有其它模块的mk文件指定了preloaded-classes覆盖了framework模块,例如…...
爬虫案例五多进程与多线程爬取斗图网
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、多进程与多线程爬取斗图网总结 前言 提示:这里可以添加本文要记录的大概内容: 爬取斗图网 提示:以下是本篇文章正文内…...
Redis的CPU高达90%时如何处理
Redis的CPU高达90%时如何处理 1. 分析和优化2. 扩展和分片3. 缓存策略调整4. 资源提升5. 负载均衡6. 进程调整7. 代码层面改进8. 其他 当Redis的CPU使用率高达90%时,说明Redis服务器可能处于过载状态,这可能会导致响应时间变长甚至服务中断。要处理这种…...
计算机视觉之dlib人脸关键点绘制及微笑测试
dlib人脸关键点绘制及微笑测试 目录 dlib人脸关键点绘制及微笑测试1 dlib人脸关键点1.1 dlib1.2 人脸关键点检测1.3 检测模型1.4 凸包1.5 笑容检测1.6 函数 2 人脸检测代码2.1 关键点绘制2.2 关键点连线2.3 微笑检测 1 dlib人脸关键点 1.1 dlib dlib 是一个强大的机器学习库&a…...
FPGA时序约束的几种方法
一,时钟约束 时钟约束是最基本的一个约束,因为FPGA工具是不知道你要跑多高的频率的,你必要要告诉工具你要跑的时钟频率。时钟约束也就是经常看到的Fmax,因为Fmax是针对“最差劲路径”,也就是说,如果该“最差劲路径”得到好成绩,那些不是最差劲的路径的成绩当然比…...
【0013】Python数据类型-列表类型详解
如果你觉得我的文章写的不错,请关注我哟,请点赞、评论,收藏此文章,谢谢! 本文内容体系结构如下: Python列表,作为编程中的基础数据结构,扮演着至关重要的角色。它不仅能够存储一系…...
10.RabbitMQ集群
十、集群与高可用 RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式; 在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点; 磁盘节点会把集群的所有信息(比如交换机、绑…...
Web网页开发——水果忍者
1.介绍 复刻经典小游戏——水果忍者 2.预览 3.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…...
信息安全访问控制、抗攻击技术、安全体系和评估(高软42)
系列文章目录 信息安全访问控制、抗攻击技术、安全体系和评估 文章目录 系列文章目录前言一、信息安全技术1.访问控制2.抗攻击技术 二、欺骗技术1.ARP欺骗2.DNS欺骗3.IP欺骗 三、抗攻击技术1.端口扫描2.强化TCP/IP堆栈 四、保证体系和评估1.保证体系2.安全风险管理 五、真题在…...
【算法】009、单双链表反转
【算法】009、单双链表反转 文章目录 一、单链表反转1.1 实现思路1.2 多语言解法 二、双链表反转2.1 实现思路2.2 多语言解法 一、单链表反转 1.1 实现思路 维护 pre 变量。 从前向后遍历 head,首先记录 next head.next,其次反转指针使 head.next pr…...
物联网设备接入系统后如何查看硬件实时数据?
要在软件中实时查看硬件设备的信息,通常需要结合前后端技术来实现。以下是设计思路和实现步骤: 1. 系统架构设计 实时查看硬件设备信息的系统通常采用以下架构: 数据采集层: 硬件设备通过传感器采集数据,发送到InfluxDB。数据存…...
【Linux系统编程】初识系统编程
目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理(Process Management)2. 内存管理(Memory Management)3. 文…...
解决stylelint对deep报错
报错如图 在.stylelintrc.json的rules中配置 "selector-pseudo-class-no-unknown": [true,{"ignorePseudoClasses": ["deep"]} ]...
React基础之useInperativehandlle
通过ref调用子组件内部的focus方法来实现聚焦 与forwardRef类似,但是forwardRef是通过暴露整个Ref来实现,而useInperativehandle是通过对外暴露一个方法来实现的 import { forwardRef, useImperativeHandle, useRef, useState } from "react";…...
使用joblib 多线程/多进程
文章目录 1. Joblib 并行计算的两种模式多进程(Multiprocessing,适用于 CPU 密集型任务)多线程(Multithreading,适用于 I/O 密集型任务)2. Joblib 的基本用法3. Joblib 多进程示例(适用于 CPU 密集型任务)示例:计算平方4. Joblib 多线程示例(适用于 I/O 密集型任务)…...
⭐算法OJ⭐N-皇后问题 II【回溯剪枝】(C++实现)N-Queens II
⭐算法OJ⭐N-皇后问题【回溯剪枝】(C实现)N-Queens 问题描述 The n-queens puzzle is the problem of placing n n n queens on an n n n \times n nn chessboard such that no two queens attack each other. Given an integer n, return the num…...
【数据结构初阶】---堆的实现、堆排序以及文件中的TopK问题
1.树的概念及结构 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点&…...
ubuntu20系统下conda虚拟环境下安装文件存储位置
在 Conda 虚拟环境中执行 pip install 安装软件后,安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤: 1. 确认 Conda 虚拟环境的安装路径 查看所有环境: conda info --env…...
鸿蒙开发:RelativeContainer 相对布局详解【全套华为认证学习资料分享(考试大纲、培训教材、实验手册等等)】
前言 在最新版本的 DevEco Studio 中,官方在创建新项目时,默认使用 RelativeContainer 组件作为根布局。这足以证明 RelativeContainer 的重要性。相比其他容器组件,它极大地简化了复杂 UI 布局中的元素对齐问题。 例如,在没有 R…...
从零到一:Vision Pro工业视觉软件安装与配置实战指南
1. Vision Pro工业视觉软件入门指南 第一次接触Vision Pro的朋友可能会被这个强大的工业视觉软件震撼到。作为康耐视的拳头产品,它在汽车制造、电子检测、包装印刷等行业应用广泛。我刚开始用的时候也是一头雾水,但跟着正确的步骤走,其实安装…...
Ubuntu 18.04双网卡实战:5分钟搞定内网穿透+NAT转发(含DHCP自动分配)
Ubuntu 18.04双网卡配置全指南:从内网穿透到自动化管理 在实验室环境或小型办公网络中,经常需要一台主机同时连接内外网。Ubuntu 18.04作为长期支持版本,其网络功能稳定可靠,特别适合作为网关设备。本文将手把手教你如何配置双网卡…...
智慧医疗泡罩药板药片缺失缺陷检测数据集VOC+YOLO格式1300张3类别
注意数据集中图片大约500张是原图剩余为增强图片数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数):1300标注数量(xml文件个数):1300…...
DeOldify开源贡献指南:如何参与项目改进与代码提交
DeOldify开源贡献指南:如何参与项目改进与代码提交 想为DeOldify这个酷炫的图片上色项目添砖加瓦,但又觉得开源贡献这事儿门槛太高,不知道从何下手?别担心,你绝对不是一个人。很多人对开源既向往又畏惧,总…...
别再死记硬背公式了!用3Blue1Brown的几何动画,5分钟搞懂行列式到底是啥
用动画解锁行列式的几何直觉:从死记硬背到可视化理解 当你第一次在课本上看到行列式的计算公式时,是否感到困惑——这个看似随意的ad-bc到底意味着什么?为什么它能够决定矩阵是否可逆?传统教学往往让我们陷入计算的泥潭࿰…...
告别重复劳动:用快马生成自动化脚本,实现dify多环境一键部署与高效管理
在团队协作中,dify的部署工作常常成为效率瓶颈。每次新版本发布或环境迁移时,手动配置docker-compose文件、处理版本差异、备份数据等重复操作不仅耗时,还容易出错。最近尝试用InsCode(快马)平台生成自动化脚本集,意外发现部署效率…...
BlueROV2进阶:巧用ArduSub参数配置实现多舵机协同控制
1. 从单舵机到多舵机协同的跨越 第一次用Pixhawk控制单个舵机转动时的兴奋感还记忆犹新,但当真正开始构建BlueROV2这样的水下机器人时,你会发现单一舵机控制远远不够。想象一下这样的场景:机械爪需要精准开合,云台要平稳转动&…...
Qt操作Excel避坑指南:为什么我放弃了QAxObject而选择QXlsx?
Qt操作Excel的终极方案:从QAxObject到QXlsx的技术迁移实战 三年前接手一个工业数据采集项目时,我遇到了职业生涯中最棘手的Excel导出问题。客户现场同时安装了Office 2016和WPS,导致基于QAxObject开发的报表模块随机崩溃。更糟的是࿰…...
为什么3分钟搞懂AI
炒又幕燃、RedisShake 核心介绍 RedisShake 是阿里云 Tair 开源团队推出的轻量级Redis数据处理工具,无需复杂依赖,部署简单、操作便捷,能适配自建Redis、云Redis等多种环境,解决Redis全生命周期的数据管理难题。 1.1 四大核心功能…...
二分查找/二分答案
0.前言二分算法(Binary Search),也叫折半查找,是一种在有序数据集合中高效查找目标值的算法。它通过不断将查找范围缩小一半,快速定位目标,时间复杂度为 O(logn),远优于线性查找的 O(n)。1.原理…...
