redis同步解决 缓存击穿+缓存穿透 原理代码实现

news2024/12/25 14:20:53

缓存穿透

 就是一个根本不存在的数据 请求过来,然后 发现缓存没有,就打到数据库,然后 数据库也没有,就会给数据库造成很大的压力 ,

解决方案 就是老生常谈的  返回null值,或者布隆过滤器  

我们说 返回null值     也就是 在查到数据库之后,发现数据库没有,就缓存一个null值到缓存,然后 返回回去,这样下一个请求过来了,就会读到我们redis中缓存的null值

缓存击穿

 一个热点 key 突然过期了,这时候有大量的请求突然访问过来,但是缓存过期了,请求直接打到数据库,造成数据库压力过大  

一般解决方案 有两种 

1. 用redis的互斥锁 ,保证缓存过期的时候,只有一个线程能访问数据库,然后 构建缓存,其他线程 用自旋锁一直挂起, 在挂起的时候,线程休眠一下,然后一直获取缓存 

2. 逻辑过期  原理很简单 既然缓存会过期,那你设置永不过期就行了,然后给类中添加 逻辑过期 时间,每次获得线程的时候 只要判断逻辑过期没有,逻辑过期了,就获取互斥锁,重建缓存

这样说 可能比较抽象 ,我们下面直接进行代码实现  ,保证解决缓存穿透的同时,再用互斥锁解决缓存击穿的问题

业务逻辑图

如果不理解,那就自己脑补一下多线程的情况

 下面是代码实现

获取锁的类

获得锁
 然后代码实现

根据id访问缓存

.

最后的逻辑实现
 //互斥锁解决缓存击穿
    private Result nXPassThrough(Long id) throws InterruptedException {
        Result shopMap = findShopMap(id);
        if (shopMap.getErrorMsg() == null) {
            return Result.ok(shopMap);
        }
        //解决缓存击穿
        //走到这里  代表着 缓存查不到了
        //1. 获取 redisson 互斥锁
        //2. 获取不成功 自旋等待
        while (true) {
            if (passThroughLock.tryLock()) {
                try {
                    log.info("获得到了锁");
                    //2. 获取成功查询数据库 返回缓存数据
                    //没有的话查数据库
                    Shop shopById = query().eq("id", id).one();
                    if (BeanUtil.isNotEmpty(shopById)) {
                        //数据库有的话 添加缓存并且返回
                        Result shopMap1 = findShopMap(id);
                        if (shopMap1.getErrorMsg() == null) {
                            return Result.ok(shopMap1);
                        }
                        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(shopById);
                        redisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id, stringObjectMap);
                        // 设置过期时间 防止内存 占满
                        redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY + id, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
                        return Result.ok(shopById);
                    }
                    //数据库没有 返回false
                    //解决缓存穿透   访问不存在的数据 缓存为null值 并且设置过期时间
                    log.info("缓存穿透 构建了新数据");
                    redisTemplate.opsForHash().put(RedisConstants.CACHE_SHOP_KEY + id, "nullId", "null");
                    redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY + id, RedisConstants.CACHE_NULL_TTL, TimeUnit.SECONDS);
                    return Result.ok("返回成功");
                } finally {
                    passThroughLock.unlock();
                }
            } else {
                try {
                    Thread.sleep(100);
                    Result shopMap1 = findShopMap(id);
                    if (shopMap1.getErrorMsg() == null) {
                        return Result.ok(shopMap1);
                    }
                } catch (InterruptedException e) {
                    return Result.fail(e.getMessage());
                }
            }
        }
    }
jmter压测结果

当我们访问数据库存在的数据

当我们访问数据库不存在的数据

也是同样的情况只查询到了一次sql,并且构建了新的空数据

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

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

相关文章

linux查看k8s的开机启动状态 systemctl is-enabled 查看开机启动状态

查看k8s的开机启动状态 在Kubernetes中&#xff0c;通常使用systemd来管理服务的启动。但是&#xff0c;Kubernetes节点上的服务可能不是由systemd直接管理&#xff0c;而是通过kubelet服务来管理。因此&#xff0c;检查Kubernetes节点的开机启动状态&#xff0c;你需要检查ku…

MPI程序实例:FFT算法及应用

目录 一、一维串行FFT算法 二、二维串行FFT算法 三、并行FFT算法 四、应用示例 4.1、多项式相乘 4.2 循环矩阵方程组的求解 1965年,两位美国科学家J.W.Cooley和J.W.Tukey发明了一种有效计算傅氏变换的方法,被称为FFT(Fast Fourier Transform,快速傅里叶变换)…

java中StringBuffer类和StringBuilder类常用的api

目录 1.StringBuffer类Api 1&#xff09;.构造方法 2&#xff09;.append("添加的字符串内容") 3&#xff09;.insert(int 要添加数据到指定索引后,"要添加的字符串") 4&#xff09;.delete(int 起始索引位置,int 结束索引位置) 5&#xff09;.deleteCharA…

基于SpringBoot+Vue+Uniapp微信小程序的电子竞技信息交流平台设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而…

Nginx请求头丢失,引发出来的问题

1.问题 新增的几个 header 参数是这样的&#xff1a; api_key_idapi_key_value 我配置有2层nginx转发&#xff0c;从机器A到机器B再到目标服务&#xff0c;遇到一个接口请求需要在header中传递api_key_id和api_key_value这2个参数&#xff0c;但是在EC2机器上直接curl目标服…

重塑排班新体验,搭贝员工排班系统 —— 让管理更高效,工作更顺心!

在快节奏的工作环境中&#xff0c;排班管理往往是决定团队效率与员工满意度的关键。搭贝低代码平台精心打造的员工排班系统应用&#xff0c;以直观、智能、灵活为核心&#xff0c;为您的团队带来前所未有的排班体验。 &#x1f4c5; 日历视图&#xff0c;一目了然 我们采用…

论文翻译 | Fairness-guided Few-shot Prompting for LargeLanguage Models

摘要 大型语言模型已经显示出令人惊讶的执行上下文学习的能力&#xff0c;也就是说&#xff0c;这些模型可以通过对由几个输入输出示例构建的提示进行条件反射&#xff0c;直接应用于解决大量下游任务。然而&#xff0c;先前的研究表明&#xff0c;由于训练示例、示例顺序和提示…

刷题小计六:矩阵

73.矩阵置零 mid 矩阵置零 ①先使用两个变量&#xff08;row_0 & col_0&#xff09;&#xff0c;记录「首行 & 首列」是否该被置零 ②在「非首行首列」的位置&#xff0c;存储置零信息到首行首列 // 把第一行第一列作为标志位for (int i 1; i < row; i) {for (…

电动牙刷拆解学习

大厂量产的产品的寻片选型为自己设计硬件的时候芯片选型提供了参考&#xff1a; 采用这个触点的方式充电相比于tppeC来说可以很好起到防水作用&#xff1a; USB公头&#xff1a; 牙刷母头&#xff1a; 电池充电芯片来自英集芯&#xff0c;型号IP2326&#xff0c;是一颗内部集…

执行node.js获取本机Ip命令,报:Error: Cannot find module ‘ip‘错误

Error: Cannot find module ip是由于没有改模块的依赖包&#xff0c;需要进行安装&#xff0c;以管理员的身份打开命令行&#xff0c;执行npm install ip 获取当前电脑的ip地址 方法一&#xff1a; const ip require("ip")/*** 1:获取当前电脑的ip地址*/ console.…

渗透测试之 域AD渗透手法【密码喷洒技术】手法详解 以及相关示例

说明: 域内密码喷洒工具: Kerbrute DomainPasswordSpray.ps1 原理抓个包分析一下&#xff1a; 域内用户枚举攻击防御&#xff1a; 流量检测&#xff1a; 说明: 域内密码喷洒&#xff08;Password Spraying&#xff09;一般和域内用户名枚举一起使用。 域内密码喷洒工具:…

slam系列1:open3d入门笔记

1. 读写数据 这里有很多测试用的pcd文件&#xff1a; https://github.com/PointCloudLibrary/data/blob/master/tutorials/ import open3d as o3d pcd o3d.io.read_point_cloud("test.pcd") o3d.io.write_point_cloud("write.pcd", pcd, True) # 默认fa…

SF6气体密度监测仪市场研究:主要企业的市场份额已超过37.13%

SF6气体密度监测仪是一种专用于监测和测量六氟化硫&#xff08;SF6&#xff09;气体密度的设备。SF6气体因其优异的绝缘性能和灭弧能力&#xff0c;被广泛应用于电力行业&#xff0c;尤其是在气体绝缘金属封闭开关设备&#xff08;GIS&#xff09;和断路器等关键设备中。随着电…

Java 函数式编程(1 万字)

此笔记来自于B站黑马程序员 good Java 历史版本及其优势 函数式编程, Stream API 一.函数伊始函数、函数对象 函数对象 行为参数法 延迟执行 a-lambda b-方法引用 复习小测 Math::random () -> Math.random()Math::sqrt (double number) -> Math.sqrt(number)Student:…

喜大普奔!eBay英国站取消个人卖家几乎所有销售费用!

二手电商市场竞争愈发激烈&#xff0c;eBay开始放大招了&#xff01;为什么说是取消个人卖家的几乎所有销售费用呢&#xff1f;一起来了解一下—— eBay英国站个人卖家无需支付最终交易费或监管运营费&#xff0c;这大大减轻了个人卖家的交易成本。不过需要注意的是&#xff0…

后端开发——规则引擎简介(Drools)

目录 什么是规则引擎&#xff1f;规则引擎带来的好处;Drools案例规则引擎的工作原理及应用场景常见的规则引擎及对比工作流引擎与规则引擎有什么不同 什么是规则引擎&#xff1f; 规则引擎&#xff0c;听起来高大上&#xff0c;其实可以理解为一种帮助你做“决策”的工具。你可…

使用浏览器原生API实现录屏功能

好早之前写了个小deme,本来都忘了,现在无意中又翻出来了,所以也来记录一下吧! 废话不说了,直接上代码了: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content=&q…

byte[]/InputStream/MultipartFile之间进行转换

前言 问题产生&#xff1a; 最近开发项目的时候&#xff0c;遇到了文件上传对象转换的问题 -> 我在对接抖音开放平台的时候&#xff0c;有一个图片上传的接口&#xff0c;需要将byte[]转为MultipartFile 对象&#xff0c;但是发现根本没有这样的工具类&#xff0c;后面翻阅…

无人机之巡航控制篇

一、巡航控制的基本原理 无人机巡航控制的基本原理是通过传感器检测无人机的飞行状态和环境信息&#xff0c;并将其反馈给控制器。控制器根据反馈信息和任务需求&#xff0c;计算出无人机的控制指令&#xff0c;并将其发送给执行机构。执行机构根据控制器的控制指令&#xff0c…

数据结构与算法——Java实现 33.堆排序

刻意去找的东西&#xff0c;往往是找不到的。 天下万物的来和去&#xff0c;都有它的时间。 —— 24.10.10 使用堆进行排序 算法描述 1.heapify 建立大顶堆&#xff08;所有结点的父元素大于子元素&#xff09; 2.将堆顶与堆底交换(最大元素被交换到堆底)&#xff0c;缩小并…