Redis的缓存击穿与解决
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的Key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
Redis实战篇 | Kyle's Blog (cyborg2077.github.io)
目录
解决方案
互斥锁
实现
逻辑过期
实现
解决方案
互斥锁
实现
需求:修改根据id查询商铺的业务,基于互斥锁方式来解决缓存击穿问题
-
操作锁的代码 -
核心思路就是利用redis的setnx方法来表示获取锁,如果redis没有这个key,则插入成功,返回1,如果已经存在这个key,则插入失败,返回0。在StringRedisTemplate中返回true/false,我们可以根据返回值来判断是否有线程成功获取到了锁
ShopServiceImpl
public Shop queryWithMutex(Long id) {//先从Redis中查,这里的常量值是固定的前缀 + 店铺idString shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);//如果不为空(查询到了),则转为Shop类型直接返回if (StrUtil.isNotBlank(shopJson)) {Shop shop = JSONUtil.toBean(shopJson, Shop.class);return shop;}if (shopJson != null) {return null;}Shop shop = null;try {//否则去数据库中查boolean flag = tryLock(LOCK_SHOP_KEY + id);if (!flag) {Thread.sleep(50);return queryWithMutex(id);}//查不到,则将空值写入Redisshop = getById(id);if (shop == null) {stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//查到了则转为json字符串String jsonStr = JSONUtil.toJsonStr(shop);//并存入redis,设置TTLstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, jsonStr, CACHE_SHOP_TTL, TimeUnit.MINUTES);//最终把查询到的商户信息返回给前端} catch (InterruptedException e) {throw new RuntimeException(e);} finally {unLock(LOCK_SHOP_KEY + id);}return shop;}
// 尝试获取锁private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}// 释放锁private void unLock(String key){stringRedisTemplate.delete(key);}
逻辑过期
直接在redis中设计一个永久的热点key,当发现逻辑时间已过期则采用类似互斥锁方式解决缓存击穿
实现
- 需求:根据id查询商铺的业务,基于逻辑过期方式来解决缓存击穿问题
- 思路分析:当用户开始查询redis时,判断是否命中
- 如果没有命中则直接返回空数据,不查询数据库
- 如果命中,则将value取出,判断value中的过期时间是否满足
- 如果没有过期,则直接返回redis中的数据
- 如果过期,则在开启独立线程后,直接返回之前的数据,独立线程去重构数据,重构完成后再释放互斥锁
封装数据:因为现在redis中存储的数据的value需要带上过期时间,此时要么你去修改原来的实体类,要么新建一个类包含原有的数据和过期时间
步骤一- 这里我们选择新建一个实体类,包含原有数据(用万能的Object)和过期时间,这样对原有的代码没有侵入性
@Data
public class RedisData<T> {private LocalDateTime expireTime;private T data;
}
步骤二- 在ShopServiceImpl中新增方法
public void saveShop2Redis(Long id, Long expirSeconds) {Shop shop = getById(id);RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expirSeconds));stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));
}
步骤三:正式代码
正式代码我们就直接照着流程图写就好了
//这里需要声明一个线程池,因为下面我们需要新建一个现成来完成重构缓存
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);@Override
public Shop queryWithLogicalExpire(Long id) {//1. 从redis中查询商铺缓存String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);//2. 如果未命中,则返回空if (StrUtil.isBlank(json)) {return null;}//3. 命中,将json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);//3.1 将data转为Shop对象JSONObject shopJson = (JSONObject) redisData.getData();Shop shop = JSONUtil.toBean(shopJson, Shop.class);//3.2 获取过期时间LocalDateTime expireTime = redisData.getExpireTime();//4. 判断是否过期if (LocalDateTime.now().isBefore(expireTime)) {//5. 未过期,直接返回商铺信息return shop;}//6. 过期,尝试获取互斥锁boolean flag = tryLock(LOCK_SHOP_KEY + id);//7. 获取到了锁if (flag) {//8. 开启独立线程CACHE_REBUILD_EXECUTOR.submit(() -> {try {this.saveShop2Redis(id, LOCK_SHOP_TTL);} catch (Exception e) {throw new RuntimeException(e);} finally {unlock(LOCK_SHOP_KEY + id);}});//9. 直接返回商铺信息return shop;}//10. 未获取到锁,直接返回商铺信息return shop;
}
相关文章:
Redis的缓存击穿与解决
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的Key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。 Redis实战篇 | Kyles Blog (cyborg2077.github.io) 目录 解决方案 互斥锁 实现 逻辑过期 实现 解决方案…...
网络层 IP协议【计算机网络】【协议格式 || 分片 || 网段划分 || 子网掩码】
博客主页:花果山~程序猿-CSDN博客 文章分栏:Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长! 目录 一,前提 二&…...
Python学习笔记14:进阶篇(三)。类的终结篇,类的导入和模块的导入。
前言 这篇文章属于类知识的最后一篇,带一点点其他知识,学习内容来自于Python crash course。 关注我私信发送Python crash course,分享一份中文版PDF。 类的导入 在学习的时候,包括之前,我都是在一个文件中把所有代…...
C++ lambda表达式举例
C lambda表达式 Lambda表达式是一种简洁的方式来创建匿名函数,可以直接在函数调用的地方定义,主要用于简化代码。 Lambda表达式的基本语法如下: [capture](parameters) -> return_type {// function body };示例1:基本用法 …...
持续总结中!2024年面试必问 20 道设计模式面试题(五)
上一篇地址:持续总结中!2024年面试必问 20 道设计模式面试题(四)-CSDN博客 九、请解释代理模式(Proxy Pattern)及其类型。 代理模式(Proxy Pattern)是一种结构设计模式,…...
嵌入式面经111题答案汇总(含技术答疑)_嵌入式项目源码分享
111道嵌入式面试题答案汇总专栏链接(承诺免费技术答疑) --> 《嵌入式/C面试题解析大全》 1、简介 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业工作经验,整理超全面111道嵌入式面试…...
鸿蒙开发通信与连接:【@ohos.connectedTag (有源标签)】
有源标签 说明: 本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 import connectedTag from ohos.connectedTag;connectedTag.init init(): boolean 初始化有源标签芯片。 需要权限&#…...
在线编程工具
1.C语言在线编程 https://www.jyshare.com/compile/11/ 2.java在线编程 https://www.w3cschool.cn/tryrun/runcode1?langjava 3.Python在线编程 https://www.python123.io/index/playground/python?ivk_sa1024320u...
NSSCTF中的[WUSTCTF 2020]朴实无华、[FSCTF 2023]源码!启动! 、[LitCTF 2023]Flag点击就送! 以及相关知识点
目录 [WUSTCTF 2020]朴实无华 [FSCTF 2023]源码!启动! [LitCTF 2023]Flag点击就送! 相关知识点 1.intval 绕过 绕过的方式: 2.session伪造攻击 [WUSTCTF 2020]朴实无华 1.进入页面几乎没什么可用的信息,所以想到使用dis…...
Vue49-props属性
一、当同一个组件标签被使用多次 因为data属性写的是函数形式! 二、需求:老王也想用<Student>组件,但是需要动态把老王想要的值传进来。 2-1、使用props属性接收参数 使用props属性,接收的这三个参数,是被保存在…...
CVE-2020-1957 漏洞复现
先声明一下,免杀还是会更的,不过中间可能会穿插一下渗透的内容!!! 踩坑点: 在一开始翻阅了CSDN之后,发现不同文章之间存在出入,于是最后去了CVE的官方文档,和参考一些国…...
网工内推 | 中国电信、香港宽频系统工程师,CCIE认证优先,最高年薪25w
01 中国电信股份有限公司浙江分公司 🔷招聘岗位:系统架构师 🔷岗位职责: 1、做好客户网络和信息安全产品的解决方案支撑、交付及后续运营维护,做好相关产数项目的支撑。 2、根据信息安全管理要求,负责客户…...
LLVM后端 td文件 tablegen 模式匹配 寄存器 指令集 calling convention
目录 一、寄存器 1.1 寄存器定义 1.2 寄存器分类 二、指令集 2.1 指令集定义 2.2 模式匹配 2.2.1 PatFrags与PatFrag 2.2.2 OutPatFrag 2.2.3 PatLeaf 2.2.4 ImmLeaf 2.2.5 IntImmLeaf和FPImmLeaf 2.2.6 Pat 2.2.7 ComplexPattern 2.3 指令合法化 2.3.1 Promote…...
嵌入式交叉编译:frp
参考 LINUX FRP下载编译_linux编译frpc-CSDN博客 编译 make -f Makefile.cross-compiles 检查 $ make -f Makefile.cross-compiles Build darwin-amd64... Build darwin-amd64 done Build darwin-arm64... Build darwin-arm64 done Build freebsd-amd64... Build freebsd-…...
SpringBoot实现的大文件上传
前言 大文件分片上传和断点续传是为了解决在网络传输过程中可能遇到的问题,以提高文件传输的效率和稳定性。 首先,大文件分片上传是将大文件分割成较小的片段进行上传。这样做的好处是可以减少单个文件的传输时间,因为较小的文件片段更容易快…...
【Python高级编程】用 Matplotlib 绘制迷人的图表
用 Matplotlib 绘制迷人的图表 引言 Matplotlib 是 Python 中广泛使用的绘图库,用于创建各种图表和可视化。本文将逐步指导您使用 Matplotlib 绘制基本图表,包括折线图、条形图和散点图。 安装 Matplotlib 使用 pip 安装 Matplotlib: pi…...
【UML用户指南】-19-对基本行为建模-用例图
目录 1、组成结构 2、表示法 3、一般用法 3.1、对主题的语境建模 3.2、对主题的需求建模 4、常用建模技术 4.1、对系统的语境建模 4.1.1、设计过程 4.2、对系统的需求建模 4.2.1、设计过程: 5、正向工程 UML 中的用例图是对系统的动态方面建模的 5 种图之…...
mysql密码过期的修改(Your password has expired. ..)
参考文章:mysql密码过期的修改方法(your password has expired)_我是知青-RuoYi 若依 (csdn.net) 问题:Your password has expired. To log inyou must change it using a clientthat supports expired passwords. 解决方式&…...
vivado SLR
描述 超级逻辑区(SLR)是包含在堆叠硅中的单个FPGA芯片 互连(SSI)设备。堆叠式硅互连(SSI)技术使用无源硅 具有微凸块和硅通孔(TSV)的内插器,用于组合多个FPGA管芯 切片&a…...
【CSS】深入了解圆角属性border-radius
border-radius 是 CSS 中的一个非常有用的属性,它允许你创建具有圆角边框的元素。这个属性可以应用于一个元素的四个角,或者分别应用于每个角。下面我们将深入了解 border-radius 的使用方法和一些高级技巧。 基本用法 你可以通过为 border-radius 指定…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

