redis解决缓存穿透/击穿/雪崩

文章目录

      • 1.缓存穿透
        • 1.1 概念
        • 1.2 解决方案
          • 1.2.1 缓存空对象
          • 1.2.2 布隆过滤
        • 1.2 店铺查询使用缓存穿透解决方案
          • 1.2.1 流程
      • 2.缓存雪崩
        • 2.1 什么是缓存雪崩?
        • 2.2 雪崩解决方案
      • 3.缓存击穿
        • 3.1 什么是缓存击穿?
        • 3.2解决方案
          • 3.2.1 基于互斥锁解决缓存击穿问题(热点key问题)
          • 3.2.2 基于逻辑过期方式解决缓存击穿问题

1.缓存穿透

1.1 概念

客户端请求的数据都在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库中

在这里插入图片描述

1.2 解决方案
1.2.1 缓存空对象

在这里插入图片描述

缺点:可能存在短期不一致。数据库新增了这个id对应的数据的时候,缓存中对应的是null
优点:简单

1.2.2 布隆过滤

布隆过滤存储的是一些二进制位,把数据库的数据通过哈希算法,计算出哈希值存储到布隆过滤器中
但是他说存在不一定存在,比如我数据库某条数据删除了,布隆过滤器没有更新
在这里插入图片描述
优点:内存占用少
缺点:实现复杂,存在误判

1.2 店铺查询使用缓存穿透解决方案
1.2.1 流程

在这里插入图片描述
代码实现

public Result queryById(Long id) {String key = CACHE_SHOP_KEY+id;// 1.从redis中查询店铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判断缓存是否存在if (StrUtil.isNotBlank(shopJson)) {Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 判断命中的是否是空值if (shopJson != null) {// 返回错误信息return Result.fail("店铺不存在");}// 3.不存在,根据id查询数据库Shop shop = getById(id); // mybatisplus功能// 4.不存在,返回错误if (shop == null) {// 将空值写到redisstringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺数据不存在");}// 存在,写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(shop);}

1.缓存穿透产生的原因?
用户请求的数据再数据库和缓存中都不存在,不断发起这样的请求对数据库带来了极大压力
2.缓存穿透的解决方案是什么?
缓存null值,布隆过滤,增加id复杂度,避免被猜测规律,做好基础数据检测校验,加强用户权限

2.缓存雪崩

2.1 什么是缓存雪崩?

缓存雪崩指的是同一时段大量的缓存key同时失效或者redis服务宕机,导致大量请求到达数据库,带来巨大压力

2.2 雪崩解决方案

1.给不同的KEY的TTL添加随机值
2.利用Redis集群提高服务可用性(集群,哨兵,主从)
3.给缓存业务添加降级限流策略(某些服务不让请求)
4.给业务添加多级缓存(nginx,jvm,redis都加缓存)

3.缓存击穿

3.1 什么是缓存击穿?

也称为热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会瞬间给数据库带来极大冲击。

在这里插入图片描述

3.2解决方案

1.互斥锁
2.逻辑过期

在这里插入图片描述
在这里插入图片描述

3.2.1 基于互斥锁解决缓存击穿问题(热点key问题)

在这里插入图片描述

 /** redis锁逻辑* */// 1.获取锁public boolean tryLock(String key) {Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag); // Boolean是一个包装类型,可能为null}// 2.释放锁private void unlock(String key) {stringRedisTemplate.delete(key);}/** 缓存击穿封装函数* */public Shop queryWithMutex(Long id) {String key = CACHE_SHOP_KEY+id;// 1.从redis中查询店铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判断缓存是否存在if (StrUtil.isNotBlank(shopJson)) { // 不为空值或者空字符串Shop shop = JSONUtil.toBean(shopJson, Shop.class);return shop;}// 判断命中的是否是空值if (shopJson != null) { // 这样判断他只能是空字符串了// 返回错误信息return null;}// 4.实现缓存重建// 4.1 获取互斥锁String lockKey = "lock:shop:" + id;Shop shop = null; // mybatisplus功能try {boolean isLock = tryLock(lockKey);// 4.2 判断是否获取锁成功if (!isLock) {// 失败,休眠Thread.sleep(50);return queryWithMutex(id);}// 3.获取锁成功,根据id查询数据库// 模拟重建的延时Thread.sleep(200);shop = getById(id);// 4.不存在,返回错误if (shop == null) {// 将空值写到redisstringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}// 存在,写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {unlock(lockKey);}return shop;}
3.2.2 基于逻辑过期方式解决缓存击穿问题

在这里插入图片描述

商品中原始没有逻辑过期的字段,需要自己自定义一个

@Data
public class RedisData {private LocalDateTime expireTime;private Object data; // data存储shop数据
}

代码逻辑

 /*** 存储店铺封装逻辑过期时间*/public void saveShop2Redis(Long id, Long expireSeconds) {// 查询店铺数据Shop shop = getById(id);try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}// 封装逻辑过期时间RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));// 写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));}// 开启线程池private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);public Shop queryWithLogicalExpire(Long id) {String key = CACHE_SHOP_KEY + id;// 1.从redis中查询店铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判断缓存是否存在if (StrUtil.isBlank(shopJson)) {return null;}// 4.命中,需要把json反序列化为对象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);JSONObject data = (JSONObject) redisData.getData();Shop shop = JSONUtil.toBean(data, Shop.class);LocalDateTime expireTime = redisData.getExpireTime();//5 判断是否过期if (expireTime.isAfter(LocalDateTime.now())) {// 5.1.未过期,直接返回店铺信息return shop;}// 5.2已过期,需要缓存重建String localKey = LOCK_SHOP_KEY+id;boolean isLock = tryLock(localKey);// 5.3 判断是否获取锁成功if (isLock) {// 6.3 开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(() -> {// 重建缓存try {this.saveShop2Redis(id, 20L);} catch (Exception e) {throw new RuntimeException(e);} finally {// 释放锁unlock(localKey);}});}// 6.4 返回过期的店铺信息return shop;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十六届蓝桥杯康复训练--6

题目链接&#xff1a;790. 数的三次方根 - AcWing题库 思路&#xff1a;二分&#xff0c;注意正负号和小数判断退出的方法&#xff08;虽然正负无所谓&#xff09; 代码&#xff1a; #include<bits/stdc.h> using namespace std;#define exs 0.00000018812716007232667…

Vue学习笔记集--路由

路由 Vue Router 是 Vue.js 官方的路由管理器&#xff0c;用于在 Vue 应用程序中实现单页面应用&#xff08;SPA&#xff09;的路由功能。以下是 Vue Router 的基本使用方法&#xff1a; 安装 Vue Router 如果你使用的是 Vue 2&#xff0c;可以通过 npm 安装 Vue Router&…

【AVRCP】深度剖析 AVRCP 中 Generic Access Profile 的要求与应用

目录 一、GAP基础架构与核心要求 1.1 GAP在蓝牙体系中的定位 1.2 核心模式定义 二、AVRCP对GAP的增强要求 2.1 模式扩展规范 2.2 空闲模式过程支持 三、安全机制实现细节 3.1 认证与加密流程 3.2 安全模式要求 四、设备发现与连接建立 4.1 发现过程状态机 4.2 连接…

冒排排序相关

先说一个阿里云学生无门槛免费领一年2核4g服务器的方法&#xff1a; 阿里云服务器学生无门槛免费领一年2核4g_阿里云学生认证免费服务器-CSDN博客 当谈到排序算法时&#xff0c;冒泡排序&#xff08;Bubble Sort&#xff09;是最简单且最基础的排序算法之一。它的原理是依次比…

【Linux 下的 bash 无法正常解析, Windows 的 CRLF 换行符问题导致的】

文章目录 报错原因&#xff1a;解决办法&#xff1a;方法一&#xff1a;用 dos2unix 修复方法二&#xff1a;手动转换换行符方法三&#xff1a;VSCode 或其他编辑器手动改 总结 这个错误很常见&#xff0c;原因是你的 wait_for_gpu.sh 脚本 文件格式不对&#xff0c;具体来说…

SOFABoot-07-版本查看

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…

DeepSeek和Kimi在Neo4j中的表现

以下是2个最近爆火的人工智能工具&#xff0c; DeepSeek:DeepSeek Kimi: Kimi - 会推理解析&#xff0c;能深度思考的AI助手 1、提示词&#xff1a; 你能帮我生成一个知识图谱吗&#xff0c;等一下我会给你一篇文章&#xff0c;帮我从内容中提取关键要素&#xff0c;然后以N…

相机光学中一些疑难问题的解释

工业机器视觉系统广泛应用于自动化生产、质量控制、物体检测等领域&#xff0c;而光学原理和镜头选择是确保其精准度和高效性的关键因素。 1. 为什么镜头的最大光圈处通常成像不佳&#xff1f; 在许多摄影场景中&#xff0c;最大光圈&#xff08;例如F1.2、F1.8&#xff09;是…

蓝桥杯高频考点——并查集(心血之作)

并查集 TA Can Do What & why learningwhatwhy 原理和结构路径压缩例题讲解题解solution 1&#xff08;50分&#xff09;solution 2&#xff08;100分&#xff09; 按秩(树高)合并按大小合并 TA Can Do What & why learning what 并查集主要是解决连通块的问题&#x…

抖音视频数据获取实战:从API调用到热门内容挖掘

在短视频流量为王的时代&#xff0c;掌握抖音热门视频数据已成为内容运营、竞品分析及营销决策的关键。本文将手把手教你通过抖音开放平台API获取视频详情数据&#xff0c;并提供完整的代码实现及商业化应用思路。 一、抖音API权限申请与核心接口 抖音API需企业资质认证&…

香橙派连接摄像头过程

在香橙派上下载NoMachine 在控制电脑上也下载NoMachine sudo nmcli dev wifi connect "你的WiFi名称" password "你的WiFi密码" 连接上wifi后就可以在NoMachine连上香橙派了 &#xff08;不过前提是香橙派有安装桌面端系统&#xff08;非仅窗口端&…

SOFABoot-08-启动加速

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…

简单实用!百度AI + Raphael AI = 免费生图

简单实用&#xff01;百度AI Raphael AI 免费生图 -- ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b55eda9141d34697b05db0cd60f62b75.png#pic_center) 第一步&#xff1a;下载或截取一些好看的图片当参考图片 第二步&#xff1a;用百度AI描述你想要的图片&…

React中组件通讯与插槽

一、为DOM组件设置Props 1.用JSX语法对标签的类名进行设置属性名是className&#xff1b; 2.用JSX语法对标签的样式进行设置要使用键值对进行设置&#xff0c;带“-”时用小驼峰方法来书写&#xff1b; 3.当一个标签的属性过多时&#xff0c;可以通过JSX语法进行展开设置&am…

自定义reset50模型转换到昇腾om

目录 原始转换脚本 脚本运行报错 基于reset50 模型的自定义网络 基本网络结构 卷积模块定义示例 Bottleneck定义示例 网络定义示例 改进的转换脚本 脚本运行报错channels不匹配 脚本运行报错维度不匹配 模型输入数据的类型 tensor size NCHW和NHWC 自定义网络的通…

vue3:十一、主页面布局(进入指定菜单页面,默认锁定到左侧菜单)

一、效果 直接进入home页面&#xff0c;直接展开对应的菜单项 二、具体实现 1、菜单容器增加默认选中变量 在菜单容器中将默认展开菜单default-openeds修改为默认选中菜单default-active 2、引入useRoute方法 引入该方法为了获取当前页面的路径 import { useRoute } from …

六十天前端强化训练之第二十七天之Pinia 状态管理全解与购物车实战案例

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、Pinia 深度解析 1. Pinia 核心设计 2. 核心概念图解 3. Store 类型对比 Option Store&#xff08;选项式&#xff09; Setup Store&#xff08;组合式&#xff09; …

计算机网络技术服务管理基于Spring Boot-SSM

目录 一、引言 二、用户需求分析 三、功能介绍 ‌‌3.1.资源管理‌&#xff1a; ‌3.2.故障管理‌&#xff1a; ‌3.3.性能管理‌&#xff1a; ‌3.4.安全管理‌&#xff1a; ‌3.5.配置管理‌&#xff1a; ‌3.6.日志管理‌&#xff1a; ‌3.7.用户管理‌&#xff1…

深度学习驱动下的字符识别:挑战与创新

一、引言 1.1 研究背景 深度学习在字符识别领域具有至关重要的地位。随着信息技术的飞速发展&#xff0c;对字符识别的准确性和效率要求越来越高。字符识别作为计算机视觉领域的一个重要研究方向&#xff0c;其主要目的是将各种形式的字符转换成计算机可识别的文本信息。近年…

Java多线程与高并发专题——Future 是什么?

引入 在上一篇Callable 和 Runnable 的不同&#xff1f;的最后&#xff0c;我们有提到和 Callable 配合的有一个 Future 类&#xff0c;通过 Future 可以了解任务执行情况&#xff0c;或者取消任务的执行&#xff0c;还可获取任务执行的结果&#xff0c;这些功能都是 Runnable…