Yihui’s Blog

分布式锁的实现

日期:2026-07-11
标签:#面试 #八股 #后端 #系统设计 #场景题

一句话答案

常见实现包括数据库唯一约束、Redis SET NX PX 和 ZooKeeper/etcd 临时节点;选择取决于一致性要求、性能和故障容忍度。

对比

方案核心机制优点局限
数据库唯一索引/条件更新简单、一致性边界清晰性能较低,需处理锁记录过期
RedisSET key value NX PX性能高、实现方便主从切换和租约过期可能带来并发持锁
ZooKeeper/etcd临时节点、租约、Revision一致性强、支持监听和选主运维及调用成本更高

Redis 实现要点

  1. 加锁:随机唯一 value,单命令设置 NX 和过期时间。
  2. 解锁:Lua 脚本比较 value 后删除,避免删掉别人的锁。
  3. 长任务:看门狗续租,但必须设置最大持有时长和异常退出策略。
  4. 关键写操作:增加 fencing token,下游拒绝过期持有者。

常见错误说法

  • 错误:先 SETNX,再单独 EXPIRE。两条命令间宕机会留下死锁。
  • 错误:解锁直接 DEL。锁过期后可能删除新持有者的锁。
  • 错误:有 TTL 就绝对安全。长暂停、网络分区和主从切换仍需考虑。

面试官追问

  1. Redlock 有哪些争议?
  2. 可重入锁怎么实现?
  3. 公平锁如何实现?
  4. 锁续期时进程失联怎么办?

面试官追问参考答案

1. Redlock 有哪些争议?

争议核心是它依赖多个独立 Redis 实例、时钟和租约假设,在长暂停、网络延迟和故障恢复下仍可能出现两个客户端都认为持锁。对正确性要求高的场景,仅有租约不够,应使用共识系统并配合 fencing token;Redlock 更适合能容忍极小冲突概率的效率型锁。

2. 可重入锁怎么实现?

锁 value 记录持有者唯一标识和重入计数。同一持有者再次加锁时原子增加计数并续期,解锁时递减,减到零才删除;Redis 中应用 Lua 保证检查和修改原子性。持有者标识通常包含实例、线程和请求上下文。

3. 公平锁如何实现?

为等待者维护按到达顺序排列的队列,例如使用 ZooKeeper 临时顺序节点,只有最小节点获得锁,其他节点监听前驱。Redis 可用队列加通知实现,但要处理等待者超时、进程死亡、队首清理和惊群,复杂度明显更高。

4. 锁续期时进程失联怎么办?

租约 TTL 保证失联后最终自动释放;看门狗只能在进程健康且仍是持有者时续期。续期失败必须停止业务并禁止继续写,关键资源由 fencing token 兜底;不能因为网络恢复就沿用旧锁。

Maintained by · YihuiEdit on GitHub

Keep reading

View all posts