[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 前缀的租户隔离是一种成熟且高效的实践。

相关推荐
xiaotianyuanma2 小时前
【计算机毕业设计】基于Spring Boot的体育馆预约系统的设计与实现
java·spring boot·课程设计
2601_963870213 小时前
【计算机毕业设计】基于Spring Boot的非遗文创产品交易平台的设计与实现
java·spring boot·后端
andongni2034 小时前
后端参数校验
spring boot·后端·mybatis
2601_963870227 小时前
【计算机毕业设计】基于Spring Boot的考研信息交流平台的设计与实现
java·spring boot·后端
大模型丫丫7 小时前
Spring Boot 入门指南:从零开始构建你的第一个应用
java·spring boot·后端
gis开发之家7 小时前
日志怎么打才专业?Spring Boot 4 日志体系与 Logback 配置(生产级实战)
java·spring boot·后端·logback
2601_963870181 天前
【计算机毕业设计】基于Spring Boot的宠物领养救助平台的设计与实现
spring boot·课程设计·宠物
凤山老林1 天前
高保真集成测试:Spring Boot 结合 Testcontainers 的工程落地
spring boot·后端·集成测试
RuoyiOffice1 天前
SpringBoot3+Vue3 接口访问日志实战:@ApiAccessLog 慢接口、参数脱敏与 OperateLog 如何分工
spring boot·vue3·traceid·spring boot 3·访问日志·apiaccesslog·操作日志
林三的日常1 天前
【无标题】
java·spring boot·vscode·调试·后端开发