Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录

  • 一、介绍
  • 二、方案介绍
  • 三、Redis Docker部署
  • 四、SpringBoot3 Base代码
      • 1. 依赖配置
      • 2. 基本代码
  • 五、缓存优化代码
      • 1. 校验机制
      • 2. 布隆过滤器
      • 3. 逻辑优化

一、介绍

当一种请求,总是能越过缓存,调用数据库,就是缓存穿透。
在这里插入图片描述
比如当请求一个数据库没有的数据,那么缓存也不会有,然后就一直请求,甚至高并发去请求,对数据库压力会增大。

二、方案介绍

  1. 如果key具有某种规则,那么可以对key增加校验机制,不符合直接返回。
  2. Redisson布隆过滤器
  3. 逻辑修改,当数据库没有此数据,以nullvalue,也插入redis缓存,但设置较短的过期时间。

三、Redis Docker部署

docker-compose示例如下,redis.conf从这里下载

redis:
    container_name: redis
    image: redis:7.2
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - "6379:6379"
    command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

四、SpringBoot3 Base代码

1. 依赖配置

		<!-- redis -->
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- redis 连接线程池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.11.1</version>
        </dependency>
        <!-- redisson -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.24.3</version>
        </dependency>
spring: 
  data:
    redis:
      host: 192.168.101.65  # Redis服务器的主机名或IP地址
      port: 6379  # Redis服务器的端口号
      password:  # 用于连接Redis服务器的密码
      database: 0  # 要连接的Redis数据库的索引号
      lettuce:
        pool:
          max-active: 20  # 连接池中最大的活跃连接数
          max-idle: 10  # 连接池中最大的空闲连接数
          min-idle: 0  # 连接池中最小的空闲连接数
      timeout: 10000  # 连接超时时间(毫秒)
      lock-watchdog-timeout: 100  # Redisson的分布式锁的看门狗超时时间(毫秒)

2. 基本代码

要演示的代码很简单,就是一个携带courseId请求过来,调用下面的service函数,然后查询数据库。

@Override
    public CoursePublish getCoursePublish(Long courseId) {
        return coursePublishMapper.selectById(courseId);
    }

当我们使用redis改造时,基本代码如下

@Override
    public CoursePublish getCoursePublishCache(Long courseId) {
        String key = "content:course:publish:" + courseId;
        //先查询redis
        Object object = redisTemplate.opsForValue().get(key);
        if (object != null){
            String string = object.toString();
            CoursePublish coursePublish = JSON.parseObject(string, CoursePublish.class);
            return coursePublish;
        }else {
            //后查询数据库
            CoursePublish coursePublish = getCoursePublish(courseId);
            if (coursePublish != null){
                redisTemplate.opsForValue().set(key, JSON.toJSONString(coursePublish));
            }
            return coursePublish;
        }
    }

五、缓存优化代码

1. 校验机制

我这里的id没规则,所以加不了,跳过。

2. 布隆过滤器

读取yaml配置

@Data
@Component
@ConfigurationProperties(prefix = "spring.data.redis")
public class RedisProperties {
    private String host;
    private int port;
    private String password;
    private int database;
    private int lockWatchdogTimeout;
}

配置RedissonClient

@Slf4j
@Configuration
public class RedissionConfig {

    @Autowired
    private RedisProperties redisProperties;

    @Bean
    public RedissonClient redissonClient() {
        RedissonClient redissonClient;

        Config config = new Config();
        //starter依赖进来的redisson要以redis://开头,其他不用
        String url = "redis://"+ redisProperties.getHost() + ":" + redisProperties.getPort();
        config.useSingleServer().setAddress(url)
                //.setPassword(redisProperties.getPassword())
                .setDatabase(redisProperties.getDatabase());

        try {
            redissonClient = Redisson.create(config);
            return redissonClient;
        } catch (Exception e) {
            log.error("RedissonClient init redis url:[{}], Exception:", url, e);
            return null;
        }
    }
}

把布隆过滤器加到service,如下

	private RBloomFilter<String> bloomFilter;

    @PostConstruct
    public void init(){
        //初始化布隆过滤器
        bloomFilter = redissonClient.getBloomFilter("bloom-filter");
        bloomFilter.tryInit(100, 0.003);
        List<CoursePublish> coursePublishList = coursePublishMapper.selectList(new LambdaQueryWrapper<CoursePublish>());
        coursePublishList.forEach(coursePublish -> {
            String key = "content:course:publish:" + coursePublish.getId();
            bloomFilter.add(key);
        });
    }
    
	@Override
    public CoursePublish getCoursePublishCache(Long courseId) {
        String key = "content:course:publish:" + courseId;
        //布隆过滤器
        boolean contains = bloomFilter.contains(key);
        if (!contains){
            return null;
        }
        //先查询redis
        Object object = redisTemplate.opsForValue().get(key);
        if (object != null){
            String string = object.toString();
            CoursePublish coursePublish = JSON.parseObject(string, CoursePublish.class);
            return coursePublish;
        }else {
            //后查询数据库
            CoursePublish coursePublish = getCoursePublish(courseId);
            if (coursePublish != null){
            	bloomFilter.add(key);
                redisTemplate.opsForValue().set(key, JSON.toJSONString(coursePublish));
            }
            return coursePublish;
        }
    }

3. 逻辑优化

当数据库没有此数据,以nullvalue,也插入redis缓存,但设置较短的过期时间。

            //后查询数据库
            CoursePublish coursePublish = getCoursePublish(courseId);
            if (coursePublish != null) {
            	bloomFilter.add(key);
                redisTemplate.opsForValue().set(key, JSON.toJSONString(coursePublish));
            }else {
                redisTemplate.opsForValue().set(key, JSON.toJSONString(coursePublish), 10, TimeUnit.SECONDS);
            }
            return coursePublish;

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

新版Java面试专题视频教程——多线程篇②

新版Java面试专题视频教程——多线程篇② 0. 问题汇总0.1 线程的基础知识0.2 线程中并发安全0.3 线程池0.4 使用场景 1.线程的基础知识2.线程中并发锁3.线程池3.1 说一下线程池的核心参数&#xff08;线程池的执行原理知道嘛&#xff09;3.2 线程池中有哪些常见的阻塞队列Array…

Java Web演化史:从Servlet到SpringBoot的技术进程及未来趋势

引言 在快速演进的IT世界里&#xff0c;Java Web开发始终屹立不倒&#xff0c;它不仅承担着历史的厚重&#xff0c;也始终面向未来。 自诞生之日起&#xff0c;Java Web技术就在不断地进化&#xff0c;以适应不同时代的需求。 本文将回顾Java Web开发的重要里程碑&#xff0c;…

django rest framework 学习笔记-实战商城2

01收货地址模型类和视图定义_哔哩哔哩_bilibili 本博客借鉴至大佬的视频学习笔记 地址信息的管理&#xff1a;增删改查的实现 # 序列化器配置 class AddrSerializer(serializers.ModelSerializer):"""收货地址的模型序列化器"""class Meta:mo…

喀秋莎画中画怎么设置 喀秋莎画中画视频怎么导出 喀秋莎什么意思 camtasia studio下载

画中画视频&#xff0c;顾名思义&#xff0c;就是在一个视频中有两个画面&#xff0c;游戏解说、微课等类型的视频常常就以画中画的形式出现。作为一款专业的视频编辑软件&#xff0c;使用camtasia可以轻松地制作画中画视频并导出。接下来我将为大家介绍&#xff1a;喀秋莎画中…

HEVC视频编解码标准学习笔记-1

视频编解码标准H.265/HEVC&#xff08;High Efficiency Video Coding&#xff09;通过将视频数据编码为更高效格式&#xff0c;大幅改善了视频流的压缩效率。这里主要介绍Tile、Slice和CTU的定义&#xff0c;以及介绍这些技术组件之间的相互关系。 CTU&#xff08;编码树单元&…

Chrome插件精选 — 缓存清理

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件挑选出比较好用的一款或几款&#xff0c;尽量满足界面精致、功能齐全、设置选项丰富的使用要求&#xff0c;便于节省一个个去尝试的时间和精力。 1. Chrome清理大师…

基于深度学习的红肉新鲜过期判决系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 系统构成与流程 4.2 模型训练与优化 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...............................................…

phar反序列化原理及利用

phar是什么&#xff1f; phar 是 PHP 的一种归档文件格式&#xff0c;类似于 ZIP 或 TAR 文件&#xff0c;它可以包含多个文件和目录&#xff0c;并且可以像访问普通文件系统一样在 PHP 中进行访问。在php 5.3 或更高版本中默认开启 在php.ini中配置如下时&#xff0c;才能生成…

线性代数:线性方程组解的结构

目录 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3

docker容器常见操作

目录 一、认识容器 1.1、docker用到的内核技术 1.2、namespace 1.3、Control Group 1.4、LXC与docker区别 二、docker环境准备 2.1、安装docker 2.2、docker daemon环境管理 三、镜像、容器和仓库 3.1、镜像常见操作 3.2、配置镜像加速器 命名空间 3.3、非官方镜像仓…

亿道丨防爆工业平板哪家好丨防爆平板电脑pad:防什么?

在爆炸性环境中&#xff0c;工作安全是至关重要的。防爆工业平板作为一种特殊设计的设备&#xff0c;不仅能够抵御爆炸风险&#xff0c;还提供高效的工作性能。本文将介绍防爆工业平板的防护功能以及其在各个行业中的应用。 在许多行业&#xff0c;如石油、化工、矿山和制药等领…

【RT-DETR有效改进】Best Paper | DAttention (DAT)可变形注意力机制和动态采样点

一、本文介绍 本文给大家带来的是RT-DETR改进DAT(Vision Transformer with Deformable Attention)的教程&#xff0c;其发布于2022年CVPR2022上同时被评选为Best Paper&#xff0c;由此可以证明其是一种十分有效的改进机制&#xff0c;其主要的核心思想是&#xff1a;引入可变…

考研高数(高阶导数的计算)

1.归纳法 常见高阶导数 2.泰勒展开式 3.莱布尼兹公式 4.用导数定义证明导函数在某一点连续的例题

亿道丨三防平板电脑厂商哪家好丨麒麟系统三防平板PAD

随着科技的飞速发展&#xff0c;人们对于移动设备的需求越来越高。然而&#xff0c;在不同的行业应用场景下&#xff0c;常规的智能平板往往无法满足特殊的工作要求。&#xff0c;亿道三防平板&#xff0c;将高可靠性与卓越性能高度结合&#xff0c;为各行各业提供卓越的移动解…

stm32——hal库学习笔记(ADC)

这里写目录标题 一、ADC简介&#xff08;了解&#xff09;1.1&#xff0c;什么是ADC&#xff1f;1.2&#xff0c;常见的ADC类型1.3&#xff0c;并联比较型工作示意图1.4&#xff0c;逐次逼近型工作示意图1.5&#xff0c;ADC的特性参数1.6&#xff0c;STM32各系列ADC的主要特性 …

华为OD机试真题-用连续自然数之和来表达整数-2023年OD统一考试(C卷)---python代码免费

题目&#xff1a; 代码 """ 题目分析&#xff1a; 一个整数 连续的自然数之和表示(非负整数&#xff09;输入&#xff1a; 一个整数T[1,1000] 输出&#xff1a; 输出多个表达式&#xff0c;自然数个数最少优先输出 最后一行&#xff0c; 输出“Result : 个数…

[计网底层小探索]:实现并部署多线程并发Tcp服务器框架(基于生产者消费者模型的线程池结构)

文章目录 一.网络层与传输层协议sockaddr结构体继承体系(Linux体系)贯穿计算机系统的网络通信架构图示: 二.实现并部署多线程并发Tcp服务器框架线程池模块序列化反序列化工具模块通信信道建立模块服务器主体模块任务回调模块(根据具体应用场景可重构)Tips:DebugC代码过程中遇到…

4.Spring MVC入门

文章目录 1. HTTP协议2. Spring MVC2.1. 三层架构2.2. MVC&#xff08;解决表现层的问题&#xff09;2.3. 核心组件 3. Thymeleaf3.1. 模板引擎3.2. Thymeleaf3.3. 常用语法 代码 1. HTTP协议 网址&#xff1a;https://www.ietf.org/ &#xff08;官网网址&#xff09; https:…

oppo手机如何录屏?解锁录屏新功能!

“最近换了一款oppo手机&#xff0c;感觉它的拍照功能真的很强大。但除此之外&#xff0c;我发现oppo还有许多隐藏功能&#xff0c;比如录屏。但我尝试了很久&#xff0c;都没找到录屏的开关在哪里。有没有哪位oppo用户知道怎么打开这个功能呢&#xff1f;” 随着科技的不断发…

几个常见的C/C++语言冷知识

当涉及到C/C语言时&#xff0c;有一些冷知识可能并不为人所熟知&#xff0c;但却可以让你更深入地理解这门古老而强大的编程语言。以下是一些有趣的C/C语言冷知识。 1. 数组的下标可以是负数 在我们日常的C语言编程中&#xff0c;数组是一个非常常见的数据结构。我们习惯性地使…
最新文章