[008][租户模块]基于Caffeine的租户隔离与两级缓存实践

简介: 本文介绍基于Caffeine的租户级缓存隔离与两级缓存(Caffeine+Redis)实践,通过`AbstractRoutingCacheManager`实现按租户动态路由、延迟初始化与完全隔离,兼顾高性能与数据安全,适用于SaaS多租户系统。代码开源可参。

[008][租户模块]基于Caffeine的租户隔离与两级缓存实践

本项目代码:https://gitee.com/yunjiao-source/tutorials4j/tree/master/framework

在SaaS多租户系统中,缓存隔离是一个必须解决的问题——不同租户的数据不应相互干扰,同时又需要保证高性能。本文以一个轻量级的缓存路由框架为例,分析如何利用 Caffeine 实现租户级别的本地缓存隔离,并进一步扩展为 Caffeine + Redis 的两级缓存方案。

一、核心需求与设计目标

  • 租户隔离:每个租户拥有独立的缓存空间,避免数据窜读。
  • 动态路由:根据当前请求的租户ID,自动选择对应的缓存管理器。
  • 两级缓存:本地Caffeine(一级)提供纳秒级访问,远程Redis(二级)提供跨节点共享,兼顾性能与一致性。
  • 延迟初始化:仅在租户首次访问时创建其专属缓存管理器,避免启动时占用大量内存。

二、基础抽象:AbstractRoutingCacheManager

该抽象类模仿Spring的AbstractRoutingDataSource,作为所有路由缓存管理器的基类。

public abstract class AbstractRoutingCacheManager<T extends CacheManager> implements CacheManager {
   
    private Map<Object, T> targetCacheManagers = new ConcurrentHashMap<>();

    @Override
    public Cache getCache(String name) {
   
        return determineTargetDataSource().getCache(name);
    }

    protected CacheManager determineTargetDataSource() {
   
        Object lookupKey = determineCurrentLookupKey();
        return targetCacheManagers.computeIfAbsent(lookupKey, this::createCacheManager);
    }

    protected abstract Object determineCurrentLookupKey();
    protected abstract T createCacheManager(Object name);
}

设计要点

  • determineCurrentLookupKey():由子类实现,通常从TenantContextHolder中获取当前线程的租户ID。
  • computeIfAbsent:保证同一租户只创建一个缓存管理器实例,实现按需延迟加载。
  • 完全委托模式:所有CacheManager接口方法都转发给当前租户对应的管理器。

三、租户级Caffeine缓存管理器

public class TenantCaffeineCacheManager extends AbstractRoutingCacheManager<CaffeineCacheManager> {
   
    private final CaffeineCacheManagerCreator caffeineCacheManagerCreator;

    @Override
    protected Object determineCurrentLookupKey() {
   
        return TenantContextHolder.get();
    }

    @Override
    protected CaffeineCacheManager createCacheManager(Object name) {
   
        return caffeineCacheManagerCreator.newInstance();
    }
}

亮点

  • 每个租户获得一个独立的CaffeineCacheManager实例,底层Caffeine缓存完全隔离。
  • CaffeineCacheManagerCreator负责生产默认配置的Caffeine管理器(例如设置过期时间、最大条目等),支持后续定制。

四、两级缓存:Caffeine + Redis

多级缓存管理器MultiLevelCacheManager(未完整贴出,但从创建器可推断)组合了一级本地缓存和二级分布式缓存。其创建器如下:

public class TenantMultiLevelCacheManagerCreator implements Supplier<MultiLevelCacheManager> {
   
    private final TenantCaffeineCacheManagerCreator tenantCaffeineCacheManagerCreator;
    private final RedisCacheManagerCreator redisCacheManagerCreator;

    @Override
    public MultiLevelCacheManager get() {
   
        // 双重检查锁单例
        instance = new MultiLevelCacheManager(
            tenantCaffeineCacheManagerCreator.get(),
            redisCacheManagerCreator.get()
        );
        return instance;
    }
}

工作流程推测

  1. 读操作:先从Caffeine获取,未命中则查Redis,命中后回填Caffeine。
  2. 写操作:同时更新Redis并失效Caffeine(或更新Caffeine)。
  3. 租户维度的隔离由上下层共同保证:不同的租户使用不同的Caffeine实例,Redis中的key也会拼接租户ID前缀。

五、Spring自动配置与创建器模式

TenantCacheConfiguration提供@ConditionalOnMissingBean的Bean定义,使得使用者可以开箱即用或覆盖默认实现。

@Configuration(proxyBeanMethods = false)
public class TenantCacheConfiguration {
   
    @Bean
    @ConditionalOnMissingBean
    TenantCaffeineCacheManagerCreator tenantCaffeineCacheManagerCreator(CaffeineCacheManagerCreator caffeineCacheManagerCreator) {
   
        return new TenantCaffeineCacheManagerCreator(caffeineCacheManagerCreator);
    }

    @Bean
    @ConditionalOnMissingBean
    TenantMultiLevelCacheManagerCreator tenantMultiLevelCacheManagerCreator(
            TenantCaffeineCacheManagerCreator tenantCaffeineCacheManagerCreator,
            RedisCacheManagerCreator redisCacheManagerCreator) {
   
        return new TenantMultiLevelCacheManagerCreator(tenantCaffeineCacheManagerCreator, redisCacheManagerCreator);
    }
}

创建器模式的价值

  • 延迟单例:TenantCaffeineCacheManagerCreator保证全局只有一个路由缓存管理器实例,但内部会按需创建租户子管理器。
  • 解决循环依赖:通过Supplier接口避免Bean过早初始化,特别适合多级缓存组合场景。

六、使用场景与优势

场景 推荐方案 收益
单租户本地缓存 TenantCaffeineCacheManager 租户隔离,无脏数据
多租户共享数据(如配置) 普通CacheManager 无需隔离
高并发读 + 分布式一致性 两级缓存(Caffeine+Redis) 热数据本地命中,冷数据走Redis
租户动态创建/销毁 路由机制 + 租户上下文 无需重启,自动创建新租户管理器

性能考量

  • Caffeine是进程内缓存,同一租户的请求可以共享热点数据,大幅降低Redis压力。
  • 租户数量较多时,每个租户独立的管理器可能会产生一定内存开销(每个管理器有独立配置和缓存实例)。可通过maximumSize限制每租户缓存条目数。

七、扩展方向

  1. 动态缓存配置:不同租户可以有不同的Caffeine参数(如过期时间、最大容量)。改造createCacheManager方法,根据租户ID从配置中心获取差异化参数。
  2. 懒加载与淘汰:可在租户无活动一段时间后,移除其缓存管理器释放内存。
  3. 监控与统计:暴露每个租户的缓存命中率、大小等指标,便于运维。
  4. 多级缓存一致性:完善写操作时的广播失效机制(例如使用Redis Pub/Sub通知其他节点清理本地Caffeine)。

八、总结

这套基于AbstractRoutingCacheManager的设计,将“路由”与“具体缓存实现”解耦,实现了优雅的租户隔离。结合Caffeine的高性能和Redis的共享能力,构建了两级缓存方案,非常适合SaaS平台、多租户中间件等场景。开发者只需在请求入口设置TenantContextHolder,后续所有缓存操作即可自动路由到正确租户的命名空间,既保证了数据安全,又获得了极致性能。


附:代码文件结构

  • AbstractRoutingCacheManager.java:核心路由基类
  • TenantCaffeineCacheManager.java:租户Caffeine实现
  • TenantMultiLevelCacheManagerCreator.java:两级缓存创建器
  • TenantCacheConfiguration.java:Spring自动配置

通过这个示例,你可以轻松扩展支持Ehcache、Hazelcast等其他缓存提供者,并实现相同的租户隔离能力。

目录
相关文章
|
20天前
|
缓存 安全 搜索推荐
[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器
本文介绍Spring Boot中Caffeine缓存的灵活定制方案:通过自定义`FlexibleCaffeineCacheManager`,支持按缓存名(如users/products)独立配置过期策略、容量等参数,兼顾全局默认与个性化需求;结合线程安全创建器、属性合并机制及无缝Spring集成,实现高性能、易扩展、零侵入的本地缓存管理。(239字)
80 2
|
20天前
|
人工智能 运维 架构师
我在 AIP 智能体平台踩过的坑,都在这篇企业 AI 落地经验里了
软件架构师罗小东分享企业AI落地实战经验:聚焦AIP智能体平台建设中的真实坑点与解法——涵盖智能体全生命周期管理、多源知识库语义检索、MCP工具集成及多模型中立架构设计,强调“解决问题”而非堆砌功能。(239字)
|
20天前
|
缓存 NoSQL Java
[006][缓存模块] 两级缓存实战:基于 Caffeine + Redis 的多级缓存设计与实现
本文介绍基于Caffeine(本地)+ Redis(分布式)的两级缓存实战方案,通过自定义`MultiLevelCache`与`MultiLevelCacheManager`,实现Spring Cache标准接口下的透明多级缓存:读优先本地(纳秒级)、未命中查Redis并回填;写同步更新两级,兼顾高性能与数据共享。代码开源可直接集成。
109 0
|
19天前
|
数据采集 自然语言处理 算法
可计算元认知文本分析:肿瘤生物物理学语义基线的构建与边界信号检测
本研究首次为肿瘤生物物理学提供可计算的语义基线,揭示该学科围绕力学信号与细胞行为的核心知识结构,并量化了力学/黏附/成像阈值作为学科边界信号。相比传统综述,本工作从“学科如何说话”的元认知视角实现了可复现、可扩展、跨层次对齐的计量基准,为肿瘤生物物理学在精准医学、组织工程及材料科学中的跨学科协作提供了方法学支撑。
|
1月前
|
人工智能 安全 API
深度解析 Claude Code 在 Prompt / Context / Harness 的设计与实践
文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。
2788 75
深度解析 Claude Code 在 Prompt / Context / Harness 的设计与实践
|
1月前
|
存储 人工智能 安全
深度解析 OpenClaw 在 Prompt / Context / Harness 三个维度中的设计哲学与实践
本文的核心思路是从Prompt、Context和Harness这三个维度展开,分析OpenClaw的设计思路,提炼出其中可复用的方法论,来思考如何将这些精华的设计哲学应用到我们自己的Agent系统设计和业务落地中去。(文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。)
1249 30
深度解析 OpenClaw 在 Prompt / Context / Harness 三个维度中的设计哲学与实践
|
19天前
|
人工智能 API iOS开发
阿里云/本地零基础喂饭级部署 Hermes Agent / OpenClaw +配置免费大模型API+集成Obsidian CLI,让AI用你的知识库创作
2026年,个人知识库的价值已从“个人备忘”升级为“AI创作资产”——Obsidian凭借本地Markdown存储、双向链接、标签体系,成为知识管理的首选工具,但长期以来存在一个核心痛点:AI Agent(如OpenClaw)无法高效复用这些精心整理的知识。传统方案需将笔记向量化存入向量数据库,不仅丢失笔记结构与关系,还存在检索不透明、维护复杂等问题。
370 0
|
20天前
|
缓存 NoSQL Java
[012][缓存模块]基于 Spring Cache 的缓存操作模版,支持Caffeine缓存, Redis缓存及两级缓存
本项目基于Spring Cache抽象,提供Caffeine本地缓存、Redis分布式缓存及两级缓存(Caffeine+Redis)的统一操作模板。通过工厂模式与模板方法,封装get/put/delete/异步加载等能力,支持租户隔离、类型安全与Spring生命周期集成,显著简化缓存接入。(239字)
80 3
[012][缓存模块]基于 Spring Cache 的缓存操作模版,支持Caffeine缓存, Redis缓存及两级缓存
|
23天前
|
JSON API PHP
韩国股票实时数据 KOSPI(主板)和 KOSDAQ(创业板)的实时行情、K 线及指数数据
StockTV API全面支持韩国股市,覆盖KOSPI主板(exchangeId=60)与KOSDAQ创业板(110),提供实时行情、K线、指数等数据。需配置countryId=11及API密钥,支持HTTP/WS双协议,含PHP对接示例与关键注意事项。

热门文章

最新文章