redis多租户key前缀必须全局唯一且可路由,强制采用{tenant_id}:service:resource:格式,禁用hash tag、环境名或版本号,所有入口须校验前缀合法性并统一执行。

Redis 多租户 Key 前缀必须全局唯一且可路由
Key 前缀不是命名习惯,而是资源隔离的强制契约。一旦前缀冲突(比如两个业务都用 user:),数据就混在同一个 slot 里,Cluster 自动分片会把它们打到同一台节点——物理隔离直接失效。
实操建议:
- 前缀格式统一为
{tenant_id}:service:resource:,例如acme:auth:token:abc123,其中acme是租户标识,不可省略或动态拼接 - 禁止用环境名(如
prod_user:)或版本号(如v2_user:)替代租户标识,它们不参与路由,也无法做租户级限流/清理 - 所有客户端写入前必须校验前缀合法性,可在 SDK 层加一道
validateKeyPrefix()检查,拒绝非法前缀的SET/HSET请求
集群模式下 Hash Tag 必须慎用,否则破坏租户边界
Redis Cluster 靠 key 中 {...} 内容决定 slot,也就是所谓 Hash Tag。如果租户前缀里带 {}(比如 {acme}:user:123),那整个 {acme} 就成了 hash tag,导致所有 {acme} 开头的 key 全被塞进同一个 slot —— 看似隔离了租户,实则把单个租户的数据压垮一个节点。
常见错误现象:Moved 12345 10.0.1.5:6379 报错频发、某节点 CPU 突增、CLUSTER SLOTS 显示 slot 分布严重倾斜。
实操建议:
- 租户前缀中绝对不要包含
{或}字符;若需保留语义,可用下划线替代,如acme_user:123 - 如确需跨 key 原子操作(如
HMGET多个字段),应确保这些 key 属于同一租户且共用完整前缀,而非依赖 hash tag 强行归组 - 用
redis-cli --cluster check定期扫描 key 分布,重点看各节点的keys_per_slot是否均衡
SCAN + KEYS 清理租户数据时,前缀匹配必须带冒号结尾
按前缀删数据最常用 SCAN 配合 DEL,但 SCAN 0 MATCH acme* 会误删 acme_config、acme_log_2024 等非业务 key,尤其当运维脚本和业务 key 共享前缀时。
使用场景:租户退订、灰度下线、安全审计后的批量清理。
实操建议:
- 匹配模式必须显式写出分隔符,例如
acme:auth:*、acme:order:*,避免裸前缀acme* - 生产环境严禁用
KEYS,它会阻塞主线程;SCAN要配合COUNT 1000和游标循环,防止单次扫描超时 - 删除前先用
SCAN 0 MATCH acme:auth:* COUNT 100抽样确认范围,再上真实脚本
Redis Proxy 或客户端分片逻辑不能绕过前缀校验
有些团队用 Twemproxy 或自研 proxy 做租户路由,以为“请求进来就转发到指定实例”,结果发现 proxy 层没校验 key 前缀,恶意或错误请求直接穿透到其他租户实例——物理隔离形同虚设。
性能影响:proxy 增加 RT,但更危险的是兼容性断裂——比如 JedisCluster 自动处理 slot 重定向,而 proxy 若未同步 CLUSTER NODES 变更,会导致请求发到已下线节点。
实操建议:
- proxy 层必须解析 key,提取租户标识,并与请求上下文中的
tenant_id字段比对,不一致立即拒绝,返回ERR tenant_mismatch - 客户端 SDK 不应封装“自动补前缀”逻辑,前缀必须由业务代码显式传入,避免隐式污染
- 监控项要覆盖
tenant_prefix_mismatch_count,而不是只盯redis_errors_total
真正难的不是设计前缀规则,而是让所有写入入口——从 cron 脚本、离线任务、管理后台 API 到三方对接服务——全都遵守同一套前缀生成逻辑。漏掉一个,整套隔离体系就出现毛细裂缝。









