分布式锁
解释多个进程或节点如何协调同一资源的临时所有权,以及租约、唯一 owner、fencing token 和业务侧约束为什么比“SET NX”本身更重要。
[!info] related notes
- 所属 MOC:Distributed Systems MOC
- 前置:分布式系统、Leader Election
- 实现:Redis、etcd、Apache ZooKeeper
- 替代方案:接口幂等设计、数据库锁
分布式锁
[!abstract] 一句话定义 分布式锁让不同进程/节点围绕同一资源协调临界区。一个可用实现至少需要原子获取、Owner Identity、Lease / Session、所有者校验释放和超时恢复;高风险外部副作用还需要 Fencing Token 防止旧 Owner 继续写入。
为什么进程内 Mutex 不够
Service A process: mutex A
Service B process: mutex B
两个 Mutex 互不共享状态,不能阻止 A、B 同时修改同一外部资源。分布式锁需要一个所有参与者都认可的协调系统。
Safety 与 Liveness
Safety
同一时刻不能有两个有效 Owner 同时修改受保护资源。
Liveness
Owner 崩溃后,锁最终能被其他节点获取,系统不会永久卡死。
只追求互斥但没有过期/会话,会留下死锁;只追求自动过期但没有 Fencing,又可能让旧 Owner 继续运行。
一个基础 Lease Lock
Acquire atomically if absent
→ store unique owner token
→ set expiry / attach session
→ renew while working
→ release only if owner matches
无条件 DEL lock_key 是错误的:锁过期后可能已被新 Owner 获取,旧 Owner 再删除会破坏新锁。
Lease 过期的危险窗口
Client A acquires lock
→ long GC / process pause
→ lease expires
→ Client B acquires lock
→ A resumes and still writes external resource
协调系统认为 B 是新 Owner,但 A 的旧进程并不知道。这就是为什么仅有 TTL 不能证明外部副作用安全。
Fencing Token
每次获取锁得到单调递增 Token:
A token=41
B token=42
受保护资源记录最近 Token,并拒绝小于当前值的请求:
write(token=41) after token=42
→ reject as stale owner
Fencing 必须由真正的下游资源校验;只把 Token 记录在 Lock Service 日志里没有保护作用。
不同实现的心智模型
Redis
常见原子 SET NX PX + unique value + owner-checked release。需要认真评估复制、Failover、时钟、Lease 和 Fencing 边界。
etcd
使用 Revision、Lease 和 Transaction 构建 Lock / Election;Revision 可作为排序或 Fencing 依据,但外部资源仍要校验。
ZooKeeper
使用 Ephemeral Sequential ZNode 构建等待队列,Session 失效后节点删除;外部副作用同样需要 Epoch / Version 防旧 Owner。
能不用锁时优先什么
- 数据库 Unique Constraint;
- 乐观锁 / Compare-and-Swap;
- 状态机条件更新;
- Idempotency Key;
- 单线程 Partition / Actor;
- 消息顺序和业务 Version;
- 把数据共置到同一事务边界。
锁增加等待、故障恢复和运维复杂度,应保护真正小而明确的临界区。
锁粒度与性能
global lock → 简单但并发低
per-tenant → 隔离租户
per-entity → 并发高但 Key 和生命周期复杂
粒度过粗导致争用;过细可能遗漏跨实体不变量。锁内不要执行无界网络调用和长任务。
常见失败模式
- Lock 获取成功但响应丢失;
- Owner 执行成功但 Release 失败;
- Lease 续期失败但工作继续;
- Lock Service Failover 产生旧视图;
- Timeout 后调用方重试并重复副作用;
- Deadlock:多个资源获取顺序不一致;
- Clock Pause / GC 导致 Lease 误判。
观测重点
acquire latency / contention
hold duration
lease renewal failures
expired locks
release owner mismatch
fenced stale writes
lock waiters / timeouts
deadlock or ordering violations
设计检查表
- Acquire 和 Release 均具备原子 Owner 校验。
- Lease / Session 丢失后工作会立即停止或 Fail Closed。
- 高风险外部资源验证 Fencing Token / Version。
- 临界区短小,有明确 Timeout 和 Cancellation。
- 多锁获取顺序固定,避免分布式死锁。
- 优先评估 Unique Constraint、CAS 和 Idempotency。
- Lock 故障窗口经过 Pause、Partition 和 Failover 测试。