← 返回题目列表

分布式缓存 Key 的命名空间如何隔离?

中等 第 18 / 26 题 更新于 2026/09/30
Key 设计命名空间多租户缓存隔离
学习 AI 实战项目

简化版

缓存 Key 应显式包含环境、应用/领域、租户、实体、版本和业务 ID,例如 prod:order:tenant42:detail:v3:9001,以避免碰撞并支持迁移与治理。但前缀只是逻辑隔离,不能替代 ACL、实例/数据库隔离、配额和加密;高风险多租户场景必须在访问控制与资源层继续隔离。

详细版

命名空间解决四类问题:不同环境/应用同名 Key 覆盖,多租户越界,数据结构升级冲突,以及无法按业务统计和清理。设计应由统一 SDK 生成而非业务自由拼接,并规范字符集、长度、大小写、ID 编码、hash tag 和版本位置。

多租户 Key 必须从服务端认证上下文取得 tenantId,不能信任客户端直接传入;ACL 限制应用只能访问允许前缀,集群/账号/配额防止一个租户打满公共资源。敏感信息不要出现在 Key 明文,因为 Key 会进入日志、慢查询和监控。

版本迁移采用新 Key 双读/回填/切换,禁止线上使用 KEYS prefix:* 做批量清理;维护 Key registry、owner、TTL 默认值和 schema 文档,并用 SCAN/索引异步治理。Redis Cluster 的 {hashTag} 只用于需要同槽的原子操作,滥用会造成分片倾斜。

完整版教学

一、命名空间为什么是缓存契约

缓存集群常被多个应用、环境和租户共享。若大家都使用 user:42,测试环境可能覆盖生产同名 Key,订单服务也可能把自己的用户视图与用户服务对象混淆。Key 不是随手拼的字符串,而是定位数据、权限和生命周期的协议。

一个可读结构能让监控按前缀归属成本、让迁移并存多个版本、让清理工具找到 owner。但结构过长会放大内存:千万级 Key 每增加 20B 前缀,原始字节就多约 200MB,还未计对象开销。因此层级要明确但不堆无用词。

记忆钩子:Key 同时回答“谁的数据、什么对象、哪个版本、由谁负责”,却不能独自回答“谁有权限访问”。

二、一个实用 Key 结构

可采用 env:domain:tenant:entity:version:id[:field],顺序保持稳定。环境在物理上完全隔离时可省略 env,但不要默认所有部署都不会共享。version 表示序列化/语义版本,而不是每次内容修改都加一。

prod:order:t42:detail:v3:9001
prod:order:t42:status:v1:9001
prod:catalog:global:product:v5:sku8848

业务 ID 应做严格编码,禁止包含分隔符造成歧义。Key 生成逻辑集中在库/类型中,避免各调用方出现 order:42、orders_42 等多个别名。

三、多租户安全不能只靠前缀

把 tenantId 拼进 Key 能避免无意碰撞,但恶意或错误代码仍可构造其他租户前缀。tenantId 必须从认证后的服务端上下文注入,缓存 DAO 不接受调用方任意覆盖;连接账号通过 ACL 限制命令与可访问模式。

隔离层解决的问题典型手段
Key 前缀逻辑碰撞与归属tenant/domain prefix
代码上下文防 IDOR/越权拼 Key服务端注入 tenantId
账号 ACL限制命令与 Key 范围独立用户、最小权限
资源配额防邻居噪声内存/QPS/连接限制
物理集群高等级安全与故障隔离独立实例/VPC/密钥

高合规租户可能需要独立集群;前缀不是安全边界。

四、版本字段如何支持平滑迁移

对象字段和编码升级时直接覆盖旧 Key,会让尚未升级的客户端无法解析。使用 v2 新 Key,先发布支持读 v2、miss 回退 v1 的代码;写路径双写或从权威数据库回填 v2;观察旧客户端流量归零后再停止 v1。

阶段1:read v2 -> fallback v1;write v1 + v2
阶段2:回填/校验 v2;灰度只读 v2
阶段3:write v2;观察 v1 访问为 0
阶段4:按 TTL 自然退出或限速清理 v1

版本不能替代业务数据 version。Key schema v3 表示编码格式,value 中的 dataVersion=184 才用于防旧值覆盖新值。

五、Redis Cluster hash tag 的边界

Redis Cluster 对 {...} 中内容计算 slot。order:{9001}:detail 与 order:{9001}:items 同槽,便于事务/Lua 同时操作;但若所有租户 Key 都使用 {global},会把全量流量压到一个 slot。

同槽需求应限制在确实需要原子多 Key 操作的小聚合根内。热点拆副本时反而不能共用同一个 hash tag,否则看似多个 Key 仍在一台节点。上线前应抽样执行 CLUSTER KEYSLOT 验证分布。

跨槽操作受限也提醒我们:不要让一个业务事务依赖大量缓存 Key 的原子性,缓存通常不应成为核心事实源。

六、敏感信息、长度与可观测性

Key 常出现在 slowlog、客户端日志、监控和抓包中,因此不要把手机号、邮箱、Token 或身份证直接作为 Key。可使用内部不可逆/受控映射 ID;普通 hash 并不自动安全,低熵手机号仍可枚举。

Key 前缀可用于成本归属,但不要把完整动态 Key作为指标 label,避免高基数拖垮监控。采集受控 namespace 与 hash 后的 TopN,详细值只在授权排障工具中查看。

长度影响内存和网络。假设 1 亿 Key 平均从 40B 增到 80B,仅文本部分多约 4GB;规范要在可读性与成本间平衡。

七、治理和批量清理

建立 namespace registry,登记 owner、说明、TTL 默认值、value schema、敏感等级、预算和下线日期。SDK 强制默认 TTL 与最大 value,CI 可扫描裸字符串 Key。未知前缀先告警,不直接删除。

线上禁止 KEYS *;使用 SCAN 也要按节点、限速和断点执行,因为完整遍历仍有成本。更好的下线方式是停止新写,让 TTL 自然清理;无 TTL 旧 Key 才由后台任务按批 UNLINK,并监控数据库回源与内存。

namespace: prod:order:*:detail:v3
owner: order-platform
default_ttl_seconds: 1800
max_value_bytes: 262144
sensitivity: internal
retire_after: null

八、常见误区与追问

  • 误区:Key 带 tenantId 就完成了租户安全隔离。 还需要认证上下文、ACL、配额,必要时物理隔离。
  • 误区:Key 越详细越好。 过长前缀在海量 Key 下占用显著内存,应保留必要层级。
  • 误区:业务参数可直接作为 tenantId 拼接。 必须使用服务端认证后的租户身份,防止越权访问。
  • 误区:所有相关 Key 使用同一 hash tag 更方便。 会产生 slot 热点,只有确需同槽原子操作时使用。
  • 追问:Key 里能放手机号吗? 不建议,Key 会暴露在多种运维渠道;使用内部 ID 并控制映射。
  • 追问:版本升级为什么不直接清缓存? 全量 miss 会冲击数据库,新旧客户端也可能解析冲突,版本化迁移更安全。
  • 追问:如何清理一个旧命名空间? 停写、观察、依靠 TTL,自然退出不足时用限速 SCAN+UNLINK,并监控回源。

九、加强记忆

用“环境、领域、租户、实体、版本、ID”组成 Key,但牢记前缀只是逻辑定位。租户身份由服务端注入,ACL 和配额形成真正边界;版本化 Key 支持新旧格式并存;hash tag 只在小范围同槽原子需求中使用。最后用 registry、owner、TTL 和限速清理把命名规范变成可治理资产。