← 返回题目列表

分布式锁的 Key 应该如何设计?

中等 第 19 / 26 题 更新于 2026/10/01
分布式锁Lock Key命名空间热点
学习 AI 实战项目

简化版

锁 Key 要稳定、唯一地表示业务冲突资源,通常采用“环境:业务:资源类型:规范化ID:版本”。它既不能包含每次都变的请求 ID 导致锁不住,也不能过粗形成全局热点,还要控制长度、隐私、哈希槽和迁移兼容性。

详细版

设计从业务不变量出发,例如同一订单状态只能串行更新,可用 prod:order:state:12345:v1。所有参与者必须使用相同的大小写、编码和 ID 规范;多环境、租户或资源类型要显式隔离,不能依赖数据库默认值。

Key 本身不承载 owner,owner 应放 value 并在释放时校验。上线新格式时要防止新旧客户端锁住不同 key,可双锁过渡或版本门禁;同时监控 top key、竞争率和高基数,敏感业务标识使用 HMAC 等带密钥摘要或内部映射,避免低熵 ID 被枚举反查。

完整版教学

一、Key 表达的是冲突域

锁 key 不是缓存 key 的随意命名,而是“哪些操作必须互斥”的协议。若订单 123 的取消与发货冲突,两者必须映射到同一 key;若订单 123 与 124 独立,就应映射到不同 key。设计错误会表现为假互斥或不必要串行。

记忆钩子:不同写法映射同一冲突域,同一写法绝不能混入不同业务资源。

二、推荐结构与规范化

可采用固定字段:{env}:{tenant}:{domain}:{resource}:{id}:{version}。ID 去除无意义空格、统一大小写和字符编码,复合资源按固定顺序拼接。字段需转义或长度前缀,避免 a:b 与字段边界混淆。

prod:t42:order:state:000123:v1
prod:t42:account-pair:1001-9008:v1

账户对先排序再拼接,使 A→B 与 B→A 获得同一组合锁。

三、常见错误映射

用 requestId 做 key,每个请求都不同,完全没有互斥;只用 order-lock,所有订单串成单线程;遗漏 tenantId,两个租户相同本地 ID 会互相阻塞;依赖展示名称,改名后产生新锁空间。

错误后果修正
随机请求 ID锁不住使用资源 ID
全局常量热点缩到冲突实体
可变名称迁移断裂稳定内部 ID
原始手机号隐私泄露内部 ID/摘要

四、Key 与 Value 职责要分开

key 标识锁对象,value 标识本次持有者,通常包含随机 owner token、租约代次等。把 owner 拼到 key 会导致不同客户端操作不同锁;把资源 ID 只放 value 又无法通过原子 SET NX 竞争同一位置。释放必须比较 value,而不是仅按 key 删除。

例如 key 长期是 order:123,A 的 value 为 UUID-A;A 只能删除 value 仍为 UUID-A 的记录。

五、分片、长度和热点考虑

Redis Cluster 按 key 哈希槽路由,使用 hash tag 可让相关脚本落同槽,但把大量无关锁都放同一 tag 会制造节点热点。Key 过长增加网络和内存;摘要能缩短但要保留足够碰撞空间,并能通过受控日志反查。

每秒 5000 次申请集中在一个商品 key 时,换 key 字符串不能消除业务串行。需要分桶必须先证明不变量可拆,否则只是牺牲正确性换吞吐。

六、版本迁移如何避免双锁空间

从 v1 改到 v2 时,新旧实例并存会分别加锁,等于互斥失效。可先发布兼容客户端同时获取两种 key,完成全量升级后停止写 v1;或通过配置门禁让所有实例原子切换。双锁必须遵循统一顺序,避免迁移期死锁。

监控按 namespace 聚合申请量、竞争率、top key 和未知版本。禁止把完整高基数 key 直接放指标标签,可在日志中采样记录摘要。

共享 SDK 应为每类锁提供类型化构造函数,而不是让业务自由拼接字符串;契约测试要验证不同服务对同一资源生成完全相同的字节序列。

七、常见误区与追问

  • 误区:Key 只要全局唯一即可。 它还必须让所有冲突动作汇聚到同一位置。
  • 误区:把 UUID 放进 Key 更安全。 每次随机会让互斥完全失效。
  • 误区:前缀不同不影响。 新旧客户端前缀不一致会形成两套锁。
  • 误区:热点 Key 可以随意分桶。 不变量不可拆时分桶会允许错误并发。
  • 追问:需要包含环境吗? 共享锁集群时必须隔离,独立集群也建议显式命名。
  • 追问:敏感 ID 怎么办? 使用内部代理 ID 或带密钥摘要,并限制反查权限。
  • 追问:Key 多长合适? 保留可诊断性同时控制传输与内存,以实际规模压测。

八、加强记忆

Key 设计按“冲突域、稳定性、隔离、规范化、版本”检查:让冲突操作同 key、独立资源不同 key,用稳定内部 ID 和明确命名空间;owner 留在 value,迁移处理新旧并存,热点只能在业务允许拆分时分桶。它是跨服务协议,必须统一库、测试和监控共同守护。