使用开源项目xxl-cache构建多级缓存

xxl-cache简介

官网地址:https://www.xuxueli.com/xxl-cache/

概述

XXL-CACHE 是一个 多级缓存框架,高效组合本地缓存和分布式缓存(Redis+Caffeine),支持"多级缓存、一致性保障、TTL、Category隔离、防穿透"等能力;拥有"高性能、高扩展、灵活易用"等特性,提供高性能多级缓存解决方案;

特性

1、灵活易用: 接入灵活方便,一分钟上手;

2、多级缓存:高效组合本地缓存和分布式缓存(Redis+Caffeine),支持L1、L2级别缓存,支持多场景缓存诉求;

3、高扩展:框架进行模块化抽象设计,本地缓存、分布式缓存以及序列化方案均支持自定义扩展;

4、高性能:底层设计L1(Local)+L2(Remote)多级缓存模型,除分布式缓存之外前置在应用层设置本地缓存,高热查询前置本地处理避免远程通讯,最大化提升性能;

5、一致性保障:支持多层级、集群多节点之间缓存数据一致性保障,借助广播消息(Redis Pub/Sub)以及客户端主动过期,实现L1及L2之间以及L1各集群节点间缓存数据一致性同步;

6、TTL:支持TTL,支持缓存数据主动过期及清理;

7、Category隔离:支持自定义缓存Category分类,缓存数据存储隔离;

8、缓存风险治理:针对典型缓存风险,如缓存穿透,底层进行针对性设计进行风险防护;

9、透明接入:支持业务透明接入,屏蔽底层实现细节,降低业务开发成本,以及学习认知成本;

10、多序列化协议支持:组件化抽象Serializer,可灵活扩展更多序列化协议;如 JDK、HESSIAN2、JSON、PROTOSTUFF、KRYO 等;

架构图

实际应用

下面通过一个小demo来初步了解xxl-cache的使用方法

环境

jdk:17

springboot:3.4.2

redis:7.4.1

依赖

xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-cache-core</artifactId>
            <version>1.2.0</version>
        </dependency>
    </dependencies>

整体结构

创建配置文件

application.properties

xml 复制代码
# xxl-cache
## L1缓存(本地)提供者,默认 caffeine
xxl.cache.l1.provider=caffeine
## L1缓存最大容量,默认10000;
xxl.cache.l1.maxSize=-1
## L1缓存过期时间,单位秒,默认10min;
xxl.cache.l1.expireAfterWrite=-1
## L2缓存(分布式)提供者,默认 redis
xxl.cache.l2.provider=redis
## L2缓存序列化方式,默认 java
xxl.cache.l2.serializer=java
## L2缓存节点配置,多个节点用逗号分隔;示例 "127.0.0.1:6379,127.0.0.1:6380"
xxl.cache.l2.nodes=127.0.0.1:6379
## L2缓存用户名配置
xxl.cache.l2.user=
## L2缓存密码配置
xxl.cache.l2.password=

XxlCacheConf.java

java 复制代码
@Configuration
public class XxlCacheConf {

    @Value("${xxl.cache.l1.provider}")
    private String l1Provider;
    @Value("${xxl.cache.l1.maxSize}")
    private int maxSize;
    @Value("${xxl.cache.l1.expireAfterWrite}")
    private long expireAfterWrite;
    @Value("${xxl.cache.l2.provider}")
    private String l2Provider;
    @Value("${xxl.cache.l2.serializer}")
    private String serializer;
    @Value("${xxl.cache.l2.nodes}")
    private String nodes;
    @Value("${xxl.cache.l2.user}")
    private String user;
    @Value("${xxl.cache.l2.password}")
    private String password;

    @Bean(initMethod = "start", destroyMethod = "stop")
    public XxlCacheFactory xxlCacheFactory() {
        XxlCacheFactory xxlCacheFactory = new XxlCacheFactory();
        xxlCacheFactory.setL1Provider(l1Provider);
        xxlCacheFactory.setMaxSize(maxSize);
        xxlCacheFactory.setExpireAfterWrite(expireAfterWrite);
        xxlCacheFactory.setL2Provider(l2Provider);
        xxlCacheFactory.setSerializer(serializer);
        xxlCacheFactory.setNodes(nodes);
        xxlCacheFactory.setUser(user);
        xxlCacheFactory.setPassword(password);
        return xxlCacheFactory;
    }
}

测试

创建IndexController

java 复制代码
@Controller()
@Slf4j
public class IndexController {

    /**
     * 1、定义缓存对象,并指定 "缓存category + 过期时间"
     */
    private XxlCacheHelper.XxlCache userCache = XxlCacheHelper.getCache("user", 60 * 1000);

    @RequestMapping("/get")
    @ResponseBody
    public String index() {
        String key = "user03";

        /**
         * 2、缓存读:按照 L1 -> L2 顺序依次读取缓存,如果L1存在缓存则返回,否则读取L2缓存并同步L1;
         */
        String value = userCache.get(key);
        return "key: " + key + "<br> value: " + value;
    }

    @RequestMapping("/set")
    @ResponseBody
    public String set(@RequestParam String value) {
        String key = "user03";

        /**
         * 3、缓存写:按照 L1 -> L2 顺序依次写缓存,同时借助内部广播机制更新全局L1节点缓存;
         */
        userCache.set(key, value);
        return "Set successfully";
    }

    @RequestMapping("/delete")
    @ResponseBody
    public String delete() {
        String key = "user03";

        /**
         * 4、缓存删:按照 L1 -> L2 顺序依次删缓存,同时借助内部广播机制更新全局L1节点缓存;
         */
        userCache.del(key);
        return "Deleted successfully";
    }
}

由于是测试用,这里就将缓存的key写死为user03

使用idea的将应用复制一份,指定运行端口为8081,同时运行两个应用实例来测试数据一致性

首先向8080的get接口发送请求,此时value没有任何值

然后向set接口发送请求,将user03的值设置为123

设置成功,通过日志可以发现:xxl-cache同时设置了l1(caffeine)、l2(redis)缓存中key的值,并且进行了广播,8081收到了广播:

此时我们可以向8081的get接口发送请求,看是否能取到user03的值:

测试成功!

相关推荐
zrc00700711 分钟前
steam无法登录 steam错误 登录时出现错误。请稍后再试。解决办法 steam无法登录解决办法 湖南地区steam DNS问题解决办法
windows·经验分享·游戏·缓存·游戏程序·创业创新·玩游戏
Small-Young27 分钟前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·spring boot·mysql·postgresql·乐观锁·并发控制
CCblandy29 分钟前
缓存淘汰实测:一次全表扫描把 LRU 命中率从 46% 打到 38%,W-TinyLFU 守住 50% 却贵 11 倍
后端·python·缓存·性能优化·架构
Wang's Blog32 分钟前
Java 项目实战: 交友项目 - 小视频模块实战:访客记录、FastDFS 存储与 SpringCache 缓存
java·缓存·交友
她的男孩2 小时前
租户 A 的验证码,却用了租户 B 的 AccessKey:Forge Admin 修跨租户短信串发
java·spring boot·saas
麻瓜code2 小时前
双写一致性:为什么是“删缓存“,而不是“改缓存“
java·缓存·mybatis
小蒜学长2 小时前
基于SpringBoot+Vue的云南地区扶贫助农系统的设计与实现(代码+数据库+LW)
java·vue.js·spring boot·后端·乡村振兴
码剑客2 小时前
Gin+GORM+Redis 项目开发常见性能坑汇总(Go后端避坑指南)
redis·后端·golang·gin
RuoyiOffice2 小时前
Hyper-V+Kubernetes 搭建实战:保留 Windows,构建三节点 Linux 容器集群
linux·spring boot·kubernetes·containerd·hyper-v·微服务部署·ruoyi office
骑着蜗牛撵大象3272 小时前
Spring Boot 4.1 + Spring AI 2.0:RAG 供文、图谱供关系、MCP 供工具的 Java Agent 平台
java·spring boot·spring·微服务·知识图谱·rag·mcp