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

【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案

30分钟自学教程:Redis缓存击穿原理与解决方案

目标

  1. 理解缓存击穿的定义及核心原因。
  2. 掌握互斥锁、逻辑过期时间等预防技术。
  3. 能够通过代码实现高并发场景下的缓存保护。
  4. 学会熔断降级、热点探测等应急方案。

教程内容

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分钟:应急处理方案
  1. 熔断降级(Sentinel示例)
@SentinelResource(value = "getProduct", blockHandler = "handleBlock")  
public Product getProduct(String id) {  // 正常业务逻辑...  
}  // 熔断后返回默认数据  
public Product handleBlock(String id, BlockException ex) {  return new Product("默认商品", 0.0);  
}  
  1. 缓存预热
// 定时预热即将过期的热点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)作为一级缓存。

练习与拓展

练习

  1. 实现基于Redisson的分布式锁,并通过JMeter验证并发控制效果。
  2. 修改逻辑过期时间代码,支持动态调整过期阈值(如30分钟~2小时随机)。

推荐拓展

  1. 研究RedLock算法及其在分布式锁中的应用。
  2. 学习Redis的持久化机制(RDB/AOF)与数据恢复。
  3. 探索开源框架JetCache对缓存击穿的自动化处理方案。

相关文章:

【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案

30分钟自学教程&#xff1a;Redis缓存击穿原理与解决方案 目标 理解缓存击穿的定义及核心原因。掌握互斥锁、逻辑过期时间等预防技术。能够通过代码实现高并发场景下的缓存保护。学会熔断降级、热点探测等应急方案。 教程内容 0~2分钟&#xff1a;缓存击穿的定义与典型场景 …...

preloaded-classes裁剪

系统预加载了哪些class类&#xff1f;system/etc/preloaded-classes 修改源代码&#xff1f; frameworks\base\config\preloaded-classes 默认位置&#xff0c;如果改了不生效&#xff0c;可能有其它模块的mk文件指定了preloaded-classes覆盖了framework模块&#xff0c;例如…...

爬虫案例五多进程与多线程爬取斗图网

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、多进程与多线程爬取斗图网总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 爬取斗图网 提示&#xff1a;以下是本篇文章正文内…...

Redis的CPU高达90%时如何处理

Redis的CPU高达90%时如何处理 1. 分析和优化2. 扩展和分片3. 缓存策略调整4. 资源提升5. 负载均衡6. 进程调整7. 代码层面改进8. 其他 当Redis的CPU使用率高达90%时&#xff0c;说明Redis服务器可能处于过载状态&#xff0c;这可能会导致响应时间变长甚至服务中断。要处理这种…...

计算机视觉之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数据类型-列表类型详解

如果你觉得我的文章写的不错&#xff0c;请关注我哟&#xff0c;请点赞、评论&#xff0c;收藏此文章&#xff0c;谢谢&#xff01; 本文内容体系结构如下&#xff1a; Python列表&#xff0c;作为编程中的基础数据结构&#xff0c;扮演着至关重要的角色。它不仅能够存储一系…...

10.RabbitMQ集群

十、集群与高可用 RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式&#xff1b; 在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点&#xff1b; 磁盘节点会把集群的所有信息(比如交换机、绑…...

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&#xff0c;首先记录 next head.next&#xff0c;其次反转指针使 head.next pr…...

物联网设备接入系统后如何查看硬件实时数据?

要在软件中实时查看硬件设备的信息&#xff0c;通常需要结合前后端技术来实现。以下是设计思路和实现步骤&#xff1a; 1. 系统架构设计 实时查看硬件设备信息的系统通常采用以下架构&#xff1a; 数据采集层: 硬件设备通过传感器采集数据&#xff0c;发送到InfluxDB。数据存…...

【Linux系统编程】初识系统编程

目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理&#xff08;Process Management&#xff09;2. 内存管理&#xff08;Memory Management&#xff09;3. 文…...

解决stylelint对deep报错

报错如图 在.stylelintrc.json的rules中配置 "selector-pseudo-class-no-unknown": [true,{"ignorePseudoClasses": ["deep"]} ]...

React基础之useInperativehandlle

通过ref调用子组件内部的focus方法来实现聚焦 与forwardRef类似&#xff0c;但是forwardRef是通过暴露整个Ref来实现&#xff0c;而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-皇后问题【回溯剪枝】&#xff08;C实现&#xff09;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树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&…...

ubuntu20系统下conda虚拟环境下安装文件存储位置

在 Conda 虚拟环境中执行 pip install 安装软件后&#xff0c;安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤&#xff1a; 1. 确认 Conda 虚拟环境的安装路径 查看所有环境&#xff1a; conda info --env…...

鸿蒙开发:RelativeContainer 相对布局详解【全套华为认证学习资料分享(考试大纲、培训教材、实验手册等等)】

前言 在最新版本的 DevEco Studio 中&#xff0c;官方在创建新项目时&#xff0c;默认使用 RelativeContainer 组件作为根布局。这足以证明 RelativeContainer 的重要性。相比其他容器组件&#xff0c;它极大地简化了复杂 UI 布局中的元素对齐问题。 例如&#xff0c;在没有 R…...

SDMatte+边缘精修效果展示:羽毛建模精度、纱布透光过渡、叶片脉络保留

SDMatte边缘精修效果展示&#xff1a;羽毛建模精度、纱布透光过渡、叶片脉络保留 1. 惊艳效果开场 想象一下这样的场景&#xff1a;你需要为一件羽毛饰品拍摄产品图&#xff0c;但无论怎么调整灯光和背景&#xff0c;羽毛边缘总是显得模糊不清&#xff1b;或者当你尝试抠出一…...

PEI转染试剂及相关工具在生命科学研究中的应用解析【曼博生物官方代理Polysciences】

摘要&#xff1a;聚乙烯亚胺&#xff08;PEI&#xff09;转染试剂在基因递送、病毒载体生产等领域应用广泛。本文结合Polysciences相关产品体系&#xff0c;对PEI转染、微球技术及神经示踪染料等工具进行系统梳理。 关键词&#xff1a;PEI转染、聚乙烯亚胺、基因转染、HEK293、…...

从零到一实战:基于快马平台快速开发企业级jiyutrainer在线评测系统

今天想和大家分享一个很实用的开发经验——如何快速搭建一个企业级的在线编程评测系统。最近正好有个朋友想做一个类似jiyutrainer的编程练习平台&#xff0c;我就用InsCode(快马)平台试了试&#xff0c;效果出乎意料的好。 项目需求分析 首先明确我们需要实现的核心功能&#…...

Qwen3字幕系统Linux部署指南:从安装到性能调优

Qwen3字幕系统Linux部署指南&#xff1a;从安装到性能调优 为视频内容自动生成精准字幕的时代已经到来 还记得手动为视频添加字幕的痛苦经历吗&#xff1f;一遍遍听写、校对、调整时间轴&#xff0c;几分钟的视频往往需要花费数小时。现在&#xff0c;基于Qwen3的智能字幕系统可…...

大多数加密API都不够用:量化团队真正需要的数据到底是什么?

如果你做过加密相关开发&#xff0c;无论是&#xff1a; 量化交易数据平台研究分析风控系统 你大概率都会经历一个阶段&#xff1a; &#x1f449; API 接了一堆&#xff0c;但始终“不够用”。 常见的一个误区 很多人在刚开始做数据接入时&#xff0c;会觉得&#xff1a; …...

PCB设计实战:数字模拟隔离的元件抉择——从0Ω电阻到磁珠的精准应用

1. 数字模拟隔离的基础原理与挑战 在混合信号电路设计中&#xff0c;数字电路和模拟电路就像两个性格迥异的邻居。数字电路工作时会产生高频开关噪声&#xff0c;就像隔壁装修时的电钻声&#xff1b;而模拟电路对噪声极其敏感&#xff0c;如同正在录音的麦克风。这时候&#xf…...

gte-base-zh场景应用:电商搜索与客服问答的语义匹配实战

gte-base-zh场景应用&#xff1a;电商搜索与客服问答的语义匹配实战 1. 电商场景中的语义匹配挑战 1.1 搜索不精准的痛点分析 在电商平台上&#xff0c;用户搜索"苹果手机"却看到水果苹果的图片&#xff0c;或者输入"轻薄笔记本"却返回游戏本&#xff0…...

Qwen3-0.6B-FP8快速上手:无需CUDA环境的CPU友好型大模型对话工具指南

Qwen3-0.6B-FP8快速上手&#xff1a;无需CUDA环境的CPU友好型大模型对话工具指南 想体验大模型对话&#xff0c;但被动辄几十GB的模型和昂贵的显卡劝退&#xff1f;今天给大家介绍一个“小钢炮”——Qwen3-0.6B-FP8对话工具。它只有6亿参数&#xff0c;经过FP8量化后体积小巧&…...

二次开发入门:修改nanobot镜像适配我的OpenClaw需求

二次开发入门&#xff1a;修改nanobot镜像适配我的OpenClaw需求 1. 为什么需要定制nanobot镜像 第一次接触OpenClaw时&#xff0c;我直接使用了官方提供的标准镜像。但在实际使用中&#xff0c;发现几个痛点&#xff1a;默认的chainlit界面过于简单&#xff0c;无法展示我需要…...

QRazyBox:5分钟解决二维码修复难题的专业工具

QRazyBox&#xff1a;5分钟解决二维码修复难题的专业工具 【免费下载链接】qrazybox QR Code Analysis and Recovery Toolkit 项目地址: https://gitcode.com/gh_mirrors/qr/qrazybox 二维码已经成为现代生活中无处不在的数字桥梁&#xff0c;但你是否遇到过这样的情况&…...