Redis 分布式锁和 ZooKeeper 分布式锁怎么选?
简化版
核心区别是 CAP 取舍:Redis 锁偏 AP(性能高、可用性好,但主从切换有极小概率丢锁),ZooKeeper 锁偏 CP(一致性强、不易丢锁,但性能较低)。选型看你更在乎什么:追求高并发、高性能,且能容忍极小概率丢锁(配合业务幂等兜底)→ 选 Redis;追求强一致、正确性优先(不能出现两个客户端同时持锁)→ 选 ZooKeeper。大多数互联网高并发场景用 Redis(Redisson),金融级强一致场景用 ZK。
详细版
对比表:
| 维度 | Redis 锁 | ZooKeeper 锁 |
|---|---|---|
| CAP 定位 | AP(可用性优先) | CP(一致性优先) |
| 底层机制 | SET NX EX + Lua | 临时顺序节点 + watch |
| 防死锁 | 过期时间(需看门狗续期) | 临时节点,会话断自动删 |
| 锁超时/续期 | 要处理业务超时、看门狗续期 | 会话在就一直持有,无需续期 |
| 公平性 | 默认非公平 | 顺序节点,天然公平 FIFO |
| 惊群 | 需注意实现 | 只监听前驱,天然防惊群 |
| 可靠性 | 主从异步复制,切换可能丢锁 | 写过半确认,不易丢锁 |
| 性能 | 高(内存单点操作) | 较低(共识 + 节点操作 + watch) |
| 阻塞等待 | 需轮询/订阅实现 | watch 前驱天然阻塞唤醒 |
| 运维 | 通常已有 Redis,成本低 | 需维护 ZK 集群 |
完整版教学
一、根本差异:AP vs CP
两者最本质的区别在 CAP 取舍:
- Redis 是 AP:为了性能和可用,主从复制是异步的。加锁写主节点成功就返回,不等从节点同步。所以主节点宕机、从节点升主时,未同步的锁会丢失——存在「两个客户端同时持锁」的小概率窗口。换来的是极高的性能(内存操作、无需多节点协调)。
- ZooKeeper 是 CP:基于 ZAB 协议,写操作要过半节点确认才成功。加锁一旦返回成功,就已被多数派持久化,不会因单点故障丢失。换来强一致,代价是每次加解锁都要走共识,性能低于 Redis。
理解了这条,其余差异都是它的推论。
二、防死锁机制不同
- Redis 靠过期时间:设过期防止持锁者宕机死锁,但过期时间是两难(短了业务没做完就过期、长了宕机后等太久),要靠看门狗自动续期来缓解。
- ZooKeeper 靠临时节点:锁节点是临时的,绑定客户端会话。客户端宕机、心跳断,会话失效,ZK 自动删节点释放锁。不用设过期时间,也不用续期,更自然。
三、公平性和惊群
- Redis 默认非公平:谁抢到算谁的,没有排队顺序;实现阻塞等待要靠轮询或发布订阅。
- ZooKeeper 天然公平:顺序节点按创建先后编号,谁先来谁先得(FIFO);且每个等待者只监听前一个节点,锁释放时只唤醒下一个,天然避免惊群。这是 ZK 锁设计上更优雅的地方。
四、可靠性 vs 性能的权衡
这是选型的核心矛盾:
- 要性能:Redis 是内存操作,加解锁一次网络往返即可,QPS 可达十万级。ZK 要走共识、创建/删除节点、触发 watch,QPS 低一个量级。高并发场景 Redis 优势明显。
- 要可靠:ZK 的过半确认让锁不易丢,一致性强。如果你的业务「绝对不能两个人同时拿锁」(如涉及金钱的关键操作),ZK 更稳妥;如果偶尔丢锁能靠业务幂等/兜底消化,Redis 够用。
记忆点:Redis 锁「快但偶尔可能丢」,ZK 锁「稳但相对慢」。高并发容忍小概率丢锁选 Redis,强一致不容忍丢锁选 ZK。
五、实践中怎么选
- 绝大多数互联网业务:选 Redis(Redisson)。性能好、通常已经部署了 Redis、Redisson 封装了续期/可重入/Lua,开箱即用。丢锁是极小概率事件,配合业务层幂等、数据库唯一约束等兜底,风险可控。
- 强一致、正确性优先:选 ZooKeeper(或 etcd)。如金融核心、要求严格互斥的场景。已经用了 ZK 做注册中心/配置中心的系统,复用 ZK 做锁也顺理成章。
- 不想引入中间件、并发低:数据库锁兜底。
一个务实的观点:别把「绝对正确」全押在分布式锁上。无论 Redis 还是 ZK,都无法 100% 防住 GC 停顿等极端情况导致的「持锁者以为自己还持锁」。真正的强正确性应该在存储层再加一道校验(如 fencing token、乐观锁版本号),锁只是第一道防线。
六、常见误区与追问
这道题不能只背概念,要把「Redis 锁与 ZooKeeper 锁对比」放回真实分布式系统里解释:谁发起、谁协调、状态如何变化、失败后怎么兜底,以及它和性能、可用性、一致性的取舍。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | Redis 锁性能高、实现轻;ZooKeeper 锁一致性和排队语义更强,但成本更高 | 不要停在名词解释 |
| 流程机制 | 评估互斥强度 -> 评估性能和延迟 -> 评估故障释放方式 -> 评估可重入和公平性 -> 按场景选 Redis 或 ZooKeeper | 说明触发方、参与方、状态变化和兜底 |
| 工程取舍 | 高频缓存重建可选 Redis 锁,关键主节点选举或配置变更锁更适合 ZooKeeper/etcd | 分布式锁只能控制临界区进入,不能替代业务幂等和状态校验 |
Redis 锁与 ZooKeeper 锁对比 面试拆解:
1. 评估互斥强度
2. 评估性能和延迟
3. 评估故障释放方式
4. 评估可重入和公平性
5. 按场景选 Redis 或 ZooKeeper
记忆钩子:先说为什么单机锁失效,再说明加锁、过期、续期、解锁、防误删和故障恢复;回答时要紧扣「Redis 锁与 ZooKeeper 锁对比」这道题,不要把相邻概念混成一段泛泛的分布式套话。
- 误区:Redis 锁和 ZooKeeper 锁没有本质区别。 Redis 基于键过期,ZooKeeper 基于会话和临时顺序节点,语义不同。
- 误区:性能高就一定选 Redis。 关键强一致协调可能更需要 ZooKeeper 的一致视图。
- 误区:ZooKeeper 锁一定公平且无成本。 顺序节点可实现公平,但 watch 和写入成本更高。
- 追问:Redis 锁适合什么? 高并发、短临界区、允许工程兜底的场景。
- 追问:ZooKeeper 锁适合什么? 选主、配置变更、低频关键资源协调。
- 追问:如何回答选型? 先说一致性要求,再说性能、运维复杂度和故障恢复方式。
七、加强记忆
Redis 锁 vs ZK 锁的根本差异是 AP vs CP:Redis 主从异步复制、性能高但切换可能丢锁,靠过期时间+看门狗防死锁、默认非公平;ZK 写过半确认、一致性强不易丢锁,靠临时节点自动释放、顺序节点天然公平且防惊群,但性能较低。选型:高并发、容忍极小概率丢锁选 Redis(Redisson,最常用);强一致、正确性优先选 ZooKeeper。终极建议:别把绝对正确全押在锁上,存储层用 fencing/版本号再兜一道。