必须对redis进行租户隔离,最常用的是key前缀强制隔离(如tenant_{id}:),需覆盖所有缓存路径;租户量大时可结合redisson连接池隔离;@cacheable需通过spel或自定义cachemanager注入tenantid,且须确保异步场景下tenantcontext传递。

直接用 Redis 默认配置,所有租户共用同一套 Key 空间,必然导致数据互相覆盖或误读——这不是“能不能”,而是“不隔离就一定会出事”。必须在 Key 层或连接层做显式隔离,否则上线即高危。
Redis Key 前缀强制隔离(最轻量、最常用)
这是生产环境最普遍的做法:所有写入 Redis 的 Key 都自动加上 tenant_{id}: 前缀。不依赖连接池切换,也不改底层客户端,靠统一装饰实现。
- Spring Boot 中可用
RedisTemplate的setKeySerializer()+ 自定义StringRedisSerializer在序列化前拼接前缀,但更推荐用 AOP 或包装类拦截opsForValue().set()等调用 - 务必确保所有缓存操作路径(包括 Spring Cache 的
@Cacheable)都经过同一套前缀逻辑,否则漏一处就破防 - 前缀不能只拼
tenantId,还要考虑环境差异,例如本地开发时建议加dev_前缀,避免和测试/生产 Key 冲突 - 注意 Key 长度:过长前缀(如 UUID + 环境名 + 租户名)可能触发 Redis 4.0+ 的 Key 长度警告,建议控制在 64 字符以内
Redisson 多租户连接隔离(共享实例 + 独立连接池)
当租户量大、读写压力不均时,仅靠 Key 前缀无法解决连接争抢问题。Redisson 支持为不同租户分配独立连接池,物理上隔离资源消耗。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 启用
spring.redis.redisson.config指向 YAML 配置文件,在其中为每个租户定义singleServerConfig.address和connectionPoolSize - 实际使用中需配合
TenantContext.get()动态加载对应租户的RedissonClient实例,不能全局单例复用 - Redisson 的
prefix配置项(如spring.redis.redisson.prefix=tenant_${tenantId}_)只影响部分内部 Key(如锁、队列),不覆盖业务 Key,仍需额外处理 - 该方案会显著增加连接数,务必调大 Redis 的
maxclients并监控connected_clients指标
@Cacheable 注解如何支持租户上下文?
Spring Cache 默认不感知租户,@Cacheable("user") 对所有租户都生成相同 Key,直接失效。
- 必须自定义
CacheManager实现,重写getCache(String name)方法,返回带租户前缀的Cache实例(如tenantA_user_cache) - 更稳妥的做法是改用 SpEL 表达式动态生成 Key:
@Cacheable(value = "user", key = "'user_' + #tenantId + '_' + #id"),前提是方法参数或 ThreadLocal 能拿到tenantId - 如果用了
TenantContext,别忘了在异步线程(如@Async)里手动传递,否则TenantContext.get()返回 null,Key 缺失租户标识 - 切忌在 Key 中拼完整对象(如
#user),JSON 序列化后不稳定,易导致缓存击穿;优先用确定性字段(ID、编码)
真正麻烦的不是加前缀,而是验证它是否被**每一处**执行到了——定时任务、MQ 消费、WebFlux 异步链路、甚至 Redis Pipeline 批量操作,都可能绕过你精心设计的拦截点。上线前必须用租户 ID 打点日志,抽检各入口的 Key 格式。










