分布式锁为什么要记录持有者身份?
简化版
锁记录持有者身份,是为了让续期和释放只能作用于本次获取创建的锁。若只按 key 删除,旧客户端在自己的锁过期后可能删掉新客户端刚获得的锁;value 应使用每次获取唯一的 owner token,并通过原子比较后操作。
详细版
owner token 不能只用线程号、IP 或固定实例 ID,因为重启、并发线程和容器复制会复用身份。常见做法是 instanceId + processEpoch + randomRequestId,重入锁还需保存持有计数;释放与续期使用 Lua/CAS 原子判断 value。
身份解决的是“谁能管理这条租约”,并不能判断持有者的新旧代次。旧 owner 在租约过期后继续写资源时,需要 Fencing Token;业务请求重复仍需要幂等键。日志可记录 token 摘要用于诊断,但不应把可伪造身份交给不可信客户端。
完整版教学
一、没有身份会发生误删
A 获得 10 秒锁后暂停 15 秒;锁过期,B 随即获得同一 key。A 恢复后执行无条件删除,删掉的是 B 的锁,C 又可进入临界区。锁服务从未同时保存两条记录,但错误释放制造了三个并发执行者。
记忆钩子:key 说明锁的是谁,value 说明这一代锁属于谁。
二、正确的原子释放
身份校验与状态修改必须是锁服务眼中的一个原子操作,否则校验通过后锁仍可能换代。不同后端可以用事务、CAS 或带 owner 条件的删除实现;调用方还必须检查操作结果,不能把“请求已发出”当作释放成功。
release(key, expectedOwner):
atomically delete only if currentOwner == expectedOwner
条件不成立表示自己已不是 owner,应记录而不能扩大为无条件清理。Redis 中如何用 Lua 落实该原子条件,属于具体实现层面的另一道题。
原子操作最好返回“已修改、owner 不匹配或记录不存在”等可区分结果,便于判断是正常过期、重复释放,还是锁生命周期异常。
三、身份应怎样生成
每次成功获取都要有不可预测且几乎不重复的 token。只用 IP 会被同机多线程共享,只用线程号会在进程重启后复用,只用固定实例 ID 会让旧请求与新请求无法区分。可组合稳定实例 ID、启动 epoch 与随机 UUID,并控制长度。
| 身份方案 | 主要问题 |
|---|---|
| IP 地址 | NAT、容器与多线程复用 |
| 线程 ID | 重启后复用、跨进程冲突 |
| 固定实例 ID | 同实例不同获取无法区分 |
| 每次随机 token | 适合普通不可重入锁 |
四、续期也必须校验 Owner
旧客户端的定时器可能在锁过期后才执行。如果续期只按 key 延长 TTL,它会替 B 续期并误以为自己恢复了所有权。比较 owner 后续期能确保只有当前代租约被延长;释放、续期、重入计数修改都遵循相同原则。
客户端本地要把 token 与锁句柄绑定,不允许业务代码仅凭 key 调用 unlock。API 设计应让错误用法难以发生。
五、可重入与所有权传播
同一逻辑执行流重入时,可在 value 中保存 owner 和计数,第一次获取计数 1,再次获取加 1,只有减到 0 才删除。异步线程切换会让“当前线程”概念失效,应显式传播锁上下文,或禁止跨线程重入。
把 token 传给另一个服务等于委托管理权限,必须限制调用边界。一般只由持锁组件释放,下游接收的是 fencing 代次而非解锁凭证。
六、Owner 与 Fencing 的区别
owner token 通常只要求唯一,回答“这条锁记录是不是我的”;fencing token 必须单调,回答“这个操作是不是比资源见过的更新”。UUID owner 可防误删,却无法让数据库在 token A、B 之间判断哪个更晚。
日志记录 key hash、owner hash、获取时间和释放结果,监控 owner mismatch、锁过期与重复 unlock。owner mismatch 增多通常说明临界区超过租期或生命周期管理有 bug。
七、常见误区与追问
- 误区:只有释放时需要 owner。 续期和重入计数修改同样需要校验。
- 误区:实例 IP 可以唯一标识持有者。 IP 会复用且一个实例可能并发获取多次。
- 误区:先 GET 再 DEL 已经安全。 两条命令之间存在 ABA 竞态。
- 误区:UUID owner 能阻止旧主写数据。 资源侧无法从 UUID 判断新旧。
- 追问:token 放在哪里? 锁 value 和客户端锁句柄中,日志仅保留摘要。
- 追问:unlock 返回 0 怎么办? 视为已失去所有权,告警并停止后续副作用。
- 追问:可重入锁如何表示? owner 加计数,并原子增减至零后删除。
八、加强记忆
Owner Identity 是锁生命周期的权限凭证:获取时每代唯一,续期和释放都原子比较,避免旧客户端操作新锁。它与业务幂等、Fencing Token 各司其职——owner 防误管租约,fencing 防迟到写,幂等防同一业务重复执行。