[033][缓存模块]基于 Redisson 的租户隔离 Redis Key 前缀设计

033缓存模块基于 Redisson 的租户隔离 Redis Key 前缀设计

本项目代码: gitee.com/yunjiao-sou...

在多租户系统中,不同租户的数据必须严格隔离。Redis 作为一种高性能缓存/存储中间件,通常被多个租户共享。一个经典且高效的隔离方案是为每个租户的 Key 自动添加唯一前缀,从而在逻辑上实现命名空间分离。

本文以 tutorials4j 框架中的一段代码为例,分析如何通过函数式接口、Redisson 的 NameMapper 扩展点以及 Spring Boot 自动配置,优雅地实现租户感知的 Redis Key 前缀管理。

一、核心设计目标

  • 无侵入 :业务代码只需使用逻辑 Key(如 "user:123"),框架层自动转换为 {tenantId}:user:123
  • 高性能:前缀添加和剥离在客户端完成,无额外网络开销。
  • 可扩展:支持多种前缀策略(仅租户、租户+自定义前缀),方便按业务模块细分。
  • 与 Redisson 无缝集成 :利用 Redisson 的 NameMapper 能力,统一处理所有 Key(包括分布式锁、对象、集合等)。

二、租户前缀策略接口:RedisKeyPrefix

RedisKeyPrefix 是一个函数式接口,定义了 Key 的计算规则:

java 复制代码
@FunctionalInterface
public interface RedisKeyPrefix {
    String SEPARATOR = ":";
    String compute(String cacheName);
}

2.1 租户策略工厂方法

tenant() 方法返回一个基于当前租户 ID 的 Key 生成器:

java 复制代码
static RedisKeyPrefix tenant() {
    return name -> TenantContextHolder.get() + SEPARATOR + name;
}
  • TenantContextHolder.get() 从线程上下文中获取当前租户标识(通常通过拦截器或过滤器设置)。
  • 生成的 Key 格式:租户ID:原始Key

2.2 租户+自定义前缀策略

tenantPrefix(String prefix) 方法允许在租户 ID 后追加一个固定前缀,便于按模块分组:

java 复制代码
static RedisKeyPrefix tenantPrefix(String prefix) {
    // 处理 prefix 是否以分隔符结尾,保证格式统一
}
  • 例如 tenantPrefix("order") 生成 租户ID:order:原始Key
  • 不同业务模块(订单、用户、商品)使用不同前缀,有助于监控和管理。

2.3 反向解析:uncompute

由于 Redis 中实际存储的 Key 是带租户前缀的,当需要从外部(如监控工具或手工查询)还原逻辑 Key 时,可使用:

java 复制代码
static String uncompute(String key) {
    // 去除第一个冒号之前的内容
}
  • 示例:uncompute("tenantA:user:123")"user:123"
  • 该方法是静态工具方法,不依赖具体策略。

三、与 Redisson 的集成:PrefixNameMapper

Redisson 提供了 NameMapper 接口,允许在读写 Redis 时动态改写 Key 名。PrefixNameMapper 是其实现类:

java 复制代码
public class PrefixNameMapper implements NameMapper {
    @Override
    public String map(String s) {
        return RedisKeyPrefix.tenant().compute(s);
    }

    @Override
    public String unmap(String s) {
        return RedisKeyPrefix.uncompute(s);
    }
}
  • map:写入/查询时调用,将业务 Key 加上租户前缀。
  • unmap:当 Redisson 需要从 Redis 返回的 Key 反向推导原始 Key 时调用(较少使用,但保持对称性)。

注册到 Redisson 配置后,所有通过 Redisson 客户端操作的 Key(RBucketRMapRLock 等)都会自动应用该映射,实现全自动租户隔离。

四、Spring Boot 自动配置

RedissonConfiguration 负责在 Spring 环境中装配上述组件:

java 复制代码
@Configuration(proxyBeanMethods = false)
public class RedissonConfiguration {

    @Bean
    @ConditionalOnMissingBean
    PrefixNameMapper prefixNameMapper() {
        return new PrefixNameMapper();
    }

    @Bean
    @ConditionalOnMissingBean
    RedissonAutoConfigurationCustomizer prefixNameRedissonConfigCustomizer(
            PrefixNameMapper prefixNameMapper) {
        return config -> config.setNameMapper(prefixNameMapper);
    }
}
  • 利用 @ConditionalOnMissingBean 允许用户覆盖默认的 PrefixNameMapper,例如改用 tenantPrefix("custom") 策略。
  • 通过 RedissonAutoConfigurationCustomizer 在不修改 Redisson 自动配置源码的前提下注入 NameMapper

五、租户隔离的效果

假设有两个租户:tenant_1001tenant_1002。业务代码执行:

java 复制代码
RBucket<String> bucket = redissonClient.getBucket("user:profile:123");
bucket.set("some data");

实际 Redis 中存储的 Key 分别为:

  • tenant_1001:user:profile:123
  • tenant_1002:user:profile:123

两个租户的数据完全隔离,互不可见。如果某个租户需要清除自己的缓存,可以扫描 tenant_1001:* 模式删除,不会影响其他租户。

六、总结

通过 RedisKeyPrefix 函数式接口加 Redisson 的 NameMapper 扩展点,我们实现了一套轻量、高效、无侵入的多租户 Redis Key 隔离方案。该方案具备以下优点:

  • 透明化 :业务代码零改造,只需确保 TenantContextHolder 正确传递租户 ID。
  • 灵活性:可随时切换前缀策略(仅租户、租户+模块前缀等)。
  • 性能:前缀拼接仅发生在客户端,一次内存操作,无额外网络交互。
  • 兼容性:完全兼容 Redisson 的所有功能(分布式锁、集合、队列、发布订阅等)。

对于构建 SaaS 化应用或需要严格数据隔离的系统,这种基于 Key 前缀的租户隔离是一种成熟且高效的实践。

相关推荐
vx-Biye_Design2 小时前
springboot安阳地区研学旅游服务小程序-计算机毕业设计源码12785
java·vue.js·windows·spring boot·tomcat·maven·mybatis
隔壁阿布都2 小时前
ShedLock 分布式定时任务锁框架介绍
spring boot·分布式
地瓜伯伯2 小时前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
zhenlai20122 小时前
Vue3 + SpringBoot + AI:我做了一个股票分析工具(第1周复盘)
人工智能·spring boot·后端
Devin~Y2 小时前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
承渊政道3 小时前
飞算JavaAI 智能引导背后的多 Agent 协作机制解析:从老旧 Java 后台升级到可运行工程
java·开发语言·spring boot·安全·intellij-idea·软件工程·ai编程
llz_11211 小时前
web-第四次课后作业
前端·spring boot·web
一杯奶茶¥13 小时前
基于springboot的失物招领管理系统带万字文档 校园失物招领管理系统 失物认领管理系统java springboot vue
java·vue.js·spring boot·java项目
不能只会打代码13 小时前
边缘视频分析平台的架构设计与性能优化——从750ms到190ms的调优之路
java·spring boot·redis·性能优化·边缘计算·物联网竞赛