← 返回题目列表

分布式锁粒度如何设计?怎样避免死锁?

高频 困难 第 12 / 26 题 更新于 2026/10/01
分布式锁锁粒度死锁锁顺序
学习 AI 实战项目

简化版

锁粒度应与真正冲突的业务资源一致:过粗会降低并发、制造热点,过细会增加多锁组合与一致性复杂度。需要获取多把锁时统一全局顺序、批量原子获取或失败即释放,并用有界租约和死锁监控兜底。

详细版

先写出不变量和冲突矩阵,再选择订单、账户、租户等稳定资源 ID 作为粒度。不要用请求 ID 导致互斥失效,也不要无理由用全局锁。跨资源转账应按规范化资源键排序后获取,例如总是先锁较小 accountId,所有代码路径必须遵守同一规则。

租约只能让死锁最终解除,不能避免期间阻塞和副作用。获取多锁应设置总截止时间、失败后按逆序释放并随机退避;监控等待图、持锁 P99、超时和热点 key。可用数据库事务、CAS 或分区单写者时,优先减少多锁需求。

完整版教学

一、粒度来自业务冲突域

同一订单状态迁移互斥,锁应落在 orderId;同一账户余额变更互斥,锁应落在 accountId。两个不同订单若没有共享不变量,就不应被 tenantId 大锁串行。先画“哪些操作同时发生会破坏什么”,再决定 key,而不是从表名直接猜。

心法:锁住最小的完整不变量;既不能漏掉共同资源,也不要扩大到无关请求。

二、粗锁与细锁的取舍

粗锁 key 少、实现容易,但并行度低;细锁并行度高,却可能一次业务获取多把锁并引入死锁。层级锁还要明确父子互斥规则,否则锁住 tenant:7 并不会自动阻止另一个客户端获取 order:99。

粒度优点代价适用
全局最简单单点串行极低频运维
租户隔离租户大租户热点租户级任务
资源并发高key 与组合复杂订单、账户
字段/分片最细不变量易遗漏极端热点优化

三、死锁怎样形成

转账 T1 已持有 A 等 B,T2 已持有 B 等 A,等待图形成环。如果双方租约都是 30 秒,系统会白白阻塞到至少一个租约过期;自动续期若不识别死锁,甚至可能无限延长。

T1: lock(A) -------- waits(B)
       ^                |
       |                v
T2: waits(A) -------- lock(B)

四、统一顺序是首选预防方法

所有资源键规范化后按同一比较规则排序,例如 (resourceType, resourceId) 升序获取,释放时逆序。转账 A→B 与 B→A 都先锁较小 ID,因此不会形成相反等待边。排序规则必须进入共享库和代码审查,不能只靠文档约定。

若锁服务支持原子批量获取,可一次提交完整 key 集合,要么全部成功要么不持有任何锁。但集合很大时会扩大临界区,应限制数量。

五、超时与退避只是兜底

获取第二把锁失败后立即释放已持有锁,并在总 deadline 内随机退避。固定 100ms 重试会让两个竞争者同步碰撞;可采用 full jitter,例如第 n 次从 0..min(cap, base×2^n) 随机等待。总超时需小于上游请求预算。

租约防止进程宕机永久占锁,却可能让旧进程恢复后继续写,因此仍需 owner 校验和 fencing。不能把“30 秒后会解开”当作无死锁设计。

六、检测、观测与替代方案

可收集 owner、waiter、key 建等待图,出现环时终止代价较小的一方;大规模系统更常依靠顺序预防和超时恢复。监控多锁数量、等待时长、超时、最长持锁和 top key,并通过 Trace 展示获取顺序。

数据库内多行更新优先交给事务与数据库死锁检测;高频跨账户业务可按账户分区、用单写者或账本模型减少同时持有两把远程锁。

调整粒度时必须灰度验证互斥语义:新旧客户端若一方锁租户、一方锁资源,两套 key 不会自动互斥,迁移期需要兼容协议或停写切换。

七、常见误区与追问

  • 误区:锁越细越好。 多锁组合会提高死锁和漏锁风险。
  • 误区:有租约就没有死锁。 租约只是最终回收,期间仍会阻塞。
  • 误区:设置获取超时就是预防死锁。 它只能终止部分等待,不能消除环形成。
  • 误区:按调用方向获取账户锁即可。 反向转账会产生相反顺序。
  • 追问:层级锁如何协调? 定义意向锁或统一经过同一层级协议,不能靠 key 前缀自动生效。
  • 追问:批量获取有什么代价? 锁集合更大、占用更久,且服务端状态机更复杂。
  • 追问:线上如何定位死锁? 用 owner/waiter 构建等待图,并关联持锁 Trace。

八、加强记忆

锁粒度按“最小完整冲突域”选择:过粗损失并行,过细增加组合风险。多锁场景先规范化 key 并全局排序,失败时释放、随机退避和总超时只是兜底;再用等待图与持锁长尾验证。能靠事务、CAS 或分区所有权消除多锁时,应优先简化模型。