基于Spring Boot的多级缓存架构实现

news2025/3/10 12:28:36

基于Spring Boot的多级缓存架构实现

以下是一个基于Spring Boot的多级缓存架构实现示例


多级缓存架构实现方案

1. 依赖配置(pom.xml)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 缓存配置类
@Configuration
@EnableCaching
public class MultiLevelCacheConfig {

    // 一级缓存(本地缓存)
    @Bean
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(30, TimeUnit.SECONDS)); // 本地缓存比Redis缓存更短
        return manager;
    }

    // 二级缓存(Redis缓存)
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(5))
                .serializeValuesWith(SerializationPair.fromSerializer(RedisSerializer.json()));

        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    // 组合缓存管理器
    @Bean
    @Primary
    public CacheManager multiLevelCacheManager(
            @Qualifier("caffeineCacheManager") CacheManager level1,
            @Qualifier("redisCacheManager") CacheManager level2) {
        return new MultiLevelCacheManager(level1, level2);
    }
}
3. 多级缓存管理器实现
public class MultiLevelCacheManager implements CacheManager {

    private final CacheManager level1; // 本地缓存
    private final CacheManager level2; // Redis缓存
    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>();

    public MultiLevelCacheManager(CacheManager level1, CacheManager level2) {
        this.level1 = level1;
        this.level2 = level2;
    }

    @Override
    public Cache getCache(String name) {
        return cacheMap.computeIfAbsent(name, 
            key -> new MultiLevelCache(
                level1.getCache(name), 
                level2.getCache(name)
            ));
    }

    @Override
    public Collection<String> getCacheNames() {
        return Stream.concat(
            level1.getCacheNames().stream(),
            level2.getCacheNames().stream()
        ).collect(Collectors.toSet());
    }

    // 多级缓存实现
    static class MultiLevelCache implements Cache {
        private final Cache level1;
        private final Cache level2;
        private final String name;

        public MultiLevelCache(Cache level1, Cache level2) {
            this.level1 = level1 != null ? level1 : new NoOpCache();
            this.level2 = level2 != null ? level2 : new NoOpCache();
            this.name = level1.getName() + ":" + level2.getName();
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public Object getNativeCache() {
            return this;
        }

        @Override
        public ValueWrapper get(Object key) {
            // 先查一级缓存
            ValueWrapper value = level1.get(key);
            if (value == null) {
                // 二级缓存查询
                value = level2.get(key);
                if (value != null) {
                    // 回填一级缓存
                    level1.put(key, value.get());
                }
            }
            return value;
        }

        @Override
        public <T> T get(Object key, Class<T> type) {
            // 实现逻辑类似get方法
            T value = level1.get(key, type);
            if (value == null) {
                value = level2.get(key, type);
                if (value != null) {
                    level1.put(key, value);
                }
            }
            return value;
        }

        @Override
        public void put(Object key, Object value) {
            // 同时写入两级缓存
            level1.put(key, value);
            level2.put(key, value);
        }

        @Override
        public void evict(Object key) {
            // 同时清除两级缓存
            level1.evict(key);
            level2.evict(key);
        }

        @Override
        public void clear() {
            level1.clear();
            level2.clear();
        }
    }

    // 空缓存实现(容错)
    static class NoOpCache implements Cache {
        // 实现基础的Cache方法,返回空值
    }
}
4. 业务层使用
@Service
public class ProductService {

    @Cacheable(value = "products", key = "#id")
    public Product getProduct(Long id) {
        // 数据库查询逻辑
        return productRepository.findById(id)
               .orElseThrow(() -> new NotFoundException("Product not found"));
    }

    @CacheEvict(value = "products", key = "#product.id")
    public void updateProduct(Product product) {
        productRepository.save(product);
    }
}
5. 配置说明(application.yml)
spring:
  cache:
    multi-level:
      level1:
        ttl: 30s    # 本地缓存时间
        max-size: 1000
      level2:
        ttl: 5m     # Redis缓存时间
  redis:
    host: redis-cluster.prod
    port: 6379
    timeout: 2000ms

关键实现要点

  1. 缓存层级策略
Client Level1 Level2 DB 查询缓存 命中返回 查询二级缓存 返回结果 返回结果 查询数据库 返回数据 回填数据 返回数据 alt [二级缓存未命中] alt [未命中] Client Level1 Level2 DB
  1. 一致性保障
  • 写操作:同时清除两级缓存(@CacheEvict​)
  • 读操作:二级缓存命中后自动回填一级缓存
  • TTL策略:一级缓存TTL(30s) < 二级缓存TTL(5m)
  1. 性能优化
  • 本地缓存:使用Caffeine高性能缓存库
  • 异步回填:可扩展为异步加载(需自定义CacheLoader)
  • 批量操作:支持@Cacheable的批量查询优化

扩展建议

  1. 缓存预热
@PostConstruct
public void preloadHotData() {
    // 加载热点数据到缓存
    hotProducts.forEach(product -> 
        cacheManager.getCache("products").put(product.getId(), product));
}
  1. 监控集成
@Bean
public MeterRegistryCustomizer<MeterRegistry> cacheMetrics() {
    return registry -> {
        CaffeineCacheManager caffeine = context.getBean(CaffeineCacheManager.class);
        RedisCacheManager redis = context.getBean(RedisCacheManager.class);
        
        // 注册Caffeine监控
        CacheMetrics.monitor(registry, caffeine, "level1");
        // 注册Redis监控
        CacheMetrics.monitor(registry, redis, "level2");
    };
}
  1. 防雪崩策略
// 在MultiLevelCache.get方法中添加
ValueWrapper get(Object key) {
    try {
        // 添加分布式锁检查
        if (lockManager.tryLock(key)) {
            // 实际查询逻辑
        }
    } finally {
        lockManager.unlock(key);
    }
}

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

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

相关文章

为什么DDPG需要目标网络而A2C不需要?

在强化学习中&#xff0c;DDPG需要目标网络而A2C不需要的主要原因在于算法架构、更新方式和目标稳定性需求的差异&#xff1a; Q值估计的稳定性需求不同 DDPG的Critic网络需要估计状态-动作值函数 Q ( s , a ) Q(s,a) Q(s,a)&#xff0c;其目标值的计算涉及下一个状态的最大Q值…

蓝桥杯 C++ b组 统计子矩阵深度解析

题目大意&#xff1a;给定一个 NM 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小11&#xff0c;最大NM) 满足子矩阵中所有数的和不超过给定的整数 K&#xff1f; 前言&#xff1a;这题很容易想到二维前缀和优化&#xff0c;然后枚举子矩阵&#xff0c;但这样时间复杂度为…

YOLOv12本地部署教程——42%速度提升,让高效目标检测触手可及

YOLOv12 是“你只看一次”&#xff08;You Only Look Once, YOLO&#xff09;系列的最新版本&#xff0c;于 2025 年 2 月发布。它引入了注意力机制&#xff0c;提升了检测精度&#xff0c;同时保持了高效的实时性能。在保持速度的同时&#xff0c;显著提升了检测精度。例如&am…

认识Event Loop【1】

前言 这应该是一个系列文章&#xff0c;因为我觉得Event Loop&#xff08;事件循环&#xff09;是一件很抽象也很重要的一个机制。eventloop这个知识点处于非常杂糅的位置&#xff0c;和很多其他知识&#xff0c;如运行时、浏览器、渲染流程、数据结构、线程等等&#xff0c;也…

《Linux栈破坏了,如何还原》

【栈破坏导读】栈破坏有了解过吗&#xff1f;何为栈破坏&#xff0c;栈破坏了&#xff0c;程序会立刻引发崩溃&#xff0c;我们通过gdb去调试coredump&#xff0c;栈被破坏的栈帧是没法被恢复的&#xff0c;这也给我们调试程序带来很大的困难&#xff0c;那如何还原栈破坏的第一…

环形链表问题的探究与代码实现

在数据结构与算法的学习中&#xff0c;环形链表是一个经典的问题。它不仅考察对链表这种数据结构的理解&#xff0c;还涉及到指针操作和逻辑推理。本文将结合代码和图文&#xff0c;深入分析如何判断链表中是否有环以及如何找到环的入口点。 目录 一、判断链表中是否有环 …

【CSS3】筑基篇

目录 复合选择器后代选择器子选择器并集选择器交集选择器伪类选择器 CSS 三大特性继承性层叠性优先级 背景属性背景色背景图背景图平铺方式背景图位置背景图缩放背景图固定背景复合属性 显示模式显示模式块级元素行内元素行内块元素 转换显示模式 结构伪类选择器结构伪类选择器…

React:类组件(上)

kerwin老师我来了 类组件的创建 class组件&#xff0c;js里的类命名首字符大写&#xff0c;类里面包括构造函数&#xff0c;方法 组件类要继承React.Component才有效 必须包含render方法 import React from react class App extends React.Component{render() {return <…

Spring Cloud之注册中心之Nacos的使用

目录 Naacos 服务注册/服务发现 引⼊Spring Cloud Alibaba依赖 引入Nacos依赖 引入Load Balance依赖 配置Nacos地址 服务端调用 启动服务 Naacos Nacos是Spring Cloud Alibaba的组件, Spring Cloud Alibaba遵循Spring Cloud中定义的服务注册, 服务发现规范. 因此使⽤Na…

字符串相乘——力扣

给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3" …

基于OpenCV的车牌识别系统(源码+论文+部署教程)

运行环境 基于OpenCV的车牌识别系统运行环境如下&#xff1a; • Python: ≥ 3.5 • OpenCV: ≥ 4.0 • IDE工具&#xff1a;Visual Studio Code&#xff08;可自行选择&#xff09; • 技术栈&#xff1a;Python OpenCV Tkinte 主要功能 基于OpenCV的车牌识别系统主要…

MySQL:CRUD(增删查改)

目录 一、准备工作 二、Create 新增 1、语法 2、单行数据全列插入 3、单行数据指定列插入 4、多行数据指定列插入 5、多行数据全列插入 三、Retrieve 检索 1、语法 2、全列查询 3、指定列查询 4、查询字段为表达式 &#xff08;1&#xff09;常量表达式 &…

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器---tinyEasyMuduoWebServer

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器—tinyEasyMuduoWebServer csdn项目&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/weixin_45178775/article/details/122257814 github链接&#xff1a;https://github.com/wyewyewye/tinyEasyMuduo…

Python入门———条件、循环

目录 语句 顺序语句 条件语句 缩进和代码块 判断年份是否是闰年 空语句 pass 循环 while 循环 求5的阶乘&#xff1a; 求1&#xff01;2&#xff01;3&#xff01;4&#xff01;5&#xff01; for循环 打印1-10 打印2&#xff0c;4&#xff0c;6&#xff0c;8&#x…

InDraw6.2.3 | 甾体、核苷、黄酮类化合物实现简称命名

导语 当化学家对着屏幕输入"2-amino-1,9-dihydro-6H-purin-6-one"时&#xff0c;隔壁生物学家可能正在搜索"鸟嘌呤"&#xff1b;这种命名差异如同"火星文"与"地球语"的碰撞。现在&#xff0c;鹰谷InDraw 6.2.3版带着53种多环化合物的…

Linux中的TCP编程接口基本使用

TCP编程接口基本使用 本篇介绍 在UDP编程接口基本使用已经介绍过UDP编程相关的接口&#xff0c;本篇开始介绍TCP编程相关的接口。有了UDP编程的基础&#xff0c;理解TCP相关的接口会更加容易&#xff0c;下面将按照两个方向使用TCP编程接口&#xff1a; 基本使用TCP编程接口…

系统部署【信创名录】及其查询地址

一、信创类型 &#xff08;一&#xff09;服务器&#xff1a; 1.华为云 2.腾讯云 3.阿里云 &#xff08;二&#xff09;中央处理器&#xff08;CPU&#xff09;&#xff1a; 1.海思&#xff0c;鲲鹏920服务器 &#xff08;三&#xff09;中间件 1.人大金仓 &#xff0…

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…

Unity DOTS从入门到精通之EntityCommandBufferSystem

文章目录 前言安装 DOTS 包ECBECB可以执行的指令示例&#xff1a; 前言 DOTS&#xff08;面向数据的技术堆栈&#xff09;是一套由 Unity 提供支持的技术&#xff0c;用于提供高性能游戏开发解决方案&#xff0c;特别适合需要处理大量数据的游戏&#xff0c;例如大型开放世界游…

MySQL 索引的数据结构(详细说明)

6. MySQL 索引的数据结构(详细说明) 文章目录 6. MySQL 索引的数据结构(详细说明)1. 为什么使用索引2. 索引及其优缺点2.1 索引概述 3. InnoDB中索引的推演3.1 索引之前的查找3.2 设计索引3.3 常见索引概念1. 聚簇索引2. 二级索引&#xff08;辅助索引、非聚簇索引&#xff09;…