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

简介: 本文介绍基于Redisson的多租户Redis Key隔离方案:通过函数式接口`RedisKeyPrefix`与`NameMapper`扩展,自动为Key添加租户前缀(如`tenant1:user:123`),实现无侵入、高性能、可扩展的逻辑隔离,兼容锁/集合等全部Redisson功能。(239字)

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

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

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

一、核心设计目标

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

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

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

@FunctionalInterface
public interface RedisKeyPrefix {
   
    String SEPARATOR = ":";
    String compute(String cacheName);
}

2.1 租户策略工厂方法

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

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

2.2 租户+自定义前缀策略

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

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

2.3 反向解析:uncompute

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

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

三、与 Redisson 的集成:PrefixNameMapper

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

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 环境中装配上述组件:

@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。业务代码执行:

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

目录
相关文章
|
2月前
|
人工智能 数据挖掘 开发者
阿里云通义千问Qwen3.8-Max-Preview限时1折与夜间限时0.2折介绍:个企双版本优惠
通义千问Qwen3.8-Max-Preview是阿里云最新旗舰基座模型,参数量达2.4T,在代码工程、专业办公、数据分析等领域显著提升。Qoder CN推出限时优惠:常规时段(08:00-22:00)享1折,夜间时段(22:00-08:00)享0.2折,计费系数从0.5x降至0.05x/0.01x。活动自2026年7月19日起,覆盖Qoder全系产品及各档位用户,更新至最新版本并选择该模型即可自动生效。需注意专家团模式及子Agent调用不参与折扣。配合阿里云百炼Token Plan、轻量服务器等多项优惠,为开发者和企业提供低成本体验顶级AI模型的机会。
|
2月前
|
缓存 Java 数据库连接
[053][核心模块]Java枚举缓存与ORM集成实践
本文介绍Java枚举缓存与ORM(MyBatis/JPA)的通用集成方案:通过`EnumCache`双向哈希缓存(O(1)查找)、`BaseEnum`统一接口及自动注册的类型转换器,解决枚举查值性能低、重复编码、缓存不一致等痛点,提升可维护性与运行效率。(239字)
173 3
|
1月前
|
缓存 NoSQL 安全
[036][缓存模块]基于 Redis 自定义缓存锁的设计与实现
本文介绍基于Redis的轻量级分布式缓存锁组件,通过`@RedisLockable`注解+ AOP + Lua脚本,支持固定租期与自动续期双模式,解决缓存击穿、重复计算与资源竞争问题,具备声明式、动态Key、原子性及安全释放等特性,代码开源可扩展。(239字)
82 2
|
1月前
|
NoSQL 调度 Redis
[057][调度模块]分布式环境下定时任务的防重复执行方案
本文介绍分布式定时任务防重复执行方案,基于Redis/Redisson分布式锁,提供自动续期与固定租期两种模式,通过`key()`控制锁粒度,支持异常跳过与自定义处理,确保集群中同一任务仅单点执行。代码开源。
100 1
|
1月前
|
存储 安全 Java
[055][调度模块]Spring动态任务调度框架的设计与实现
本文设计并实现了一个基于Spring的动态任务调度框架,突破`@Scheduled`静态限制,支持运行时增删改任务、配置热加载及执行状态跟踪。核心采用`SchedulingConfigurer`与`TriggerTask`,解耦任务逻辑与调度机制,具备零侵入、线程安全、优雅停机等特性。(239字)
142 2
|
1月前
|
缓存 安全 Java
[034][公共模块]基于SpEL的方法参数表达式求值器设计与实现
本文设计并实现了基于Spring SpEL的`MethodBasedExpressionEvaluator`,支持方法参数自动映射、占位符解析、Bean引用、自定义变量注入及表达式缓存,具备类型安全、线程安全与高扩展性,适用于权限控制、日志模板、缓存Key生成等场景。(239字)
97 2
|
2月前
|
存储 缓存 NoSQL
[032][缓存模块]基于Redis Bitmap的用户行为统计实战:签到与日活分析
本文详解如何用Redis Bitmap实现高效用户行为统计:基于Spring Boot,通过`RedisBitmapUtils`封装位图操作(设位、计数、AND/OR运算),配合`UserActivityController`提供签到、DAU、连续N日/周活跃等API。空间极省、查询毫秒级,适合亿级用户场景。(239字)
152 2
|
2月前
|
存储 缓存 NoSQL
[051][缓存模块]基于 StringRedisTemplate 的多租户 Key 隔离设计与实践——以 RedisBitmapUtils 为例
本文介绍基于StringRedisTemplate的多租户Redis Key隔离方案:通过自定义TenantStringRedisSerializer,在Key序列化时自动注入租户前缀,实现透明、低侵入的租户数据隔离。以RedisBitmapUtils为例,业务代码无需感知租户ID,所有操作自动适配,兼顾安全性与易用性。(239字)
143 0
|
1月前
|
监控 调度 开发者
[056][调度模块]RunnableDecorator – 任务执行的增强装饰器
`RunnableDecorator` 是调度模块中的增强装饰器,同时实现 `Runnable` 与 `Trigger` 接口,统一管理任务执行逻辑与触发策略,支持次数限制、失败重试、初始延迟、截止日期等高级控制,并自动记录执行历史,实现业务与调度逻辑解耦。(239字)
46 0
|
1月前
|
缓存 安全 NoSQL
[035][缓存模块]Redisson 分布式锁实战:可重入锁与阻塞锁的设计与实现
本文详解Redisson分布式锁实战,封装可重入锁(支持超时等待+自动续期)与阻塞锁两大体系,结合注解+AOP实现零侵入锁管理。涵盖安全解锁、中断处理、异常分类及选型建议,助力高并发场景下数据一致性保障。(239字)
108 0