Redlock 算法是什么?它有哪些争议?
简化版
Redlock 是 Redis 作者提出的、用来解决单点/主从 Redis 分布式锁在故障切换时丢锁问题的算法。它部署 N 个(通常 5 个)相互独立的 Redis 主节点(不是主从),客户端依次向所有节点申请锁,只有在超过半数(≥N/2+1,即 5 个里拿到 3 个)节点上都加锁成功、且总耗时小于锁有效期,才算加锁成功。这样即使个别节点宕机也不影响。但它有争议——分布式系统专家 Martin Kleppmann 质疑它在时钟漂移、GC 停顿、网络延迟下并不能真正保证正确性。
详细版
为什么需要 Redlock:普通 Redis 分布式锁若用主从架构,存在丢锁风险——客户端在主节点加锁成功,但锁还没同步到从节点,主节点就宕机了,从节点升为主,新主上没有这把锁,另一个客户端又能加锁成功 → 两个客户端同时持锁。
Redlock 的做法:
- 部署 N 个完全独立的 Redis 节点(各自是 master,无主从复制关系)。
- 客户端记录开始时间,依次向 N 个节点用
SET NX PX申请锁(每个节点设一个小超时,防止卡在某个挂掉的节点)。 - 统计成功加锁的节点数和总耗时。
- 判定成功:成功节点数 ≥ N/2 + 1(多数派)且 总耗时 < 锁有效期。此时锁的实际有效时间 = 设定有效期 − 加锁耗时。
- 加锁失败(没拿到多数派或超时),就向所有节点发送解锁,释放已获得的锁。
核心思想:用「多数派」替代「单点/主从」,个别节点故障不影响整体(5 个挂 2 个还能拿到 3 个)。
完整版教学
一、主从丢锁问题的细节
单机 Redis 加锁没有一致性问题,但单机有可用性风险,所以生产常用主从 + 哨兵。问题来了:Redis 主从复制是异步的。客户端 A 在主节点 SET lock 成功,主节点还没来得及把这个 key 同步给从节点,主节点就宕机了。哨兵把从节点提升为新主,而新主上没有这把锁。此时客户端 B 来加锁,在新主上成功了——于是 A 和 B 都以为自己持有锁,互斥失效,可能导致数据错乱。Redlock 就是为了解决这个「异步复制 + 故障切换丢锁」而生。
二、Redlock 为什么用多数派
Redlock 不用主从,而是用 N 个独立节点 + 多数派。为什么多数派能防丢锁?因为要加锁成功必须拿到超过半数节点,而两个客户端不可能同时都拿到多数派(两个多数派必有交集,交集节点上 NX 只能被一个人占)。就算某几个节点宕机丢了锁,只要没到「多数派节点同时丢锁」,就不会出现两个客户端各自凑齐多数派。这和 Quorum、Raft 选主防脑裂是同一个数学原理。
三、Martin Kleppmann 的著名质疑
Redlock 发布后,分布式专家 Martin Kleppmann 写了篇著名文章质疑它,核心论点:Redlock 依赖时间假设,而分布式系统中时间不可靠。举例:
- GC 停顿 / 进程暂停:客户端 A 拿到锁后,恰好发生一次长时间 GC(几秒甚至几十秒)暂停。暂停期间锁过期了,B 拿到锁。A 从 GC 恢复后以为自己还持有锁,继续操作共享资源 → A、B 同时操作。多数派并不能防住这种「持锁者自己暂停」。
- 时钟漂移:Redlock 判断锁有效期依赖各节点的时钟,如果某节点时钟跳变,锁的过期判断就会错乱。
Kleppmann 的结论:如果你用锁只是为了效率(偶尔两个人同时做一下问题不大,比如避免重复计算),普通 Redis 锁足够;如果用锁是为了正确性(绝对不能两个人同时做,比如涉及金钱),那 Redlock 也不够可靠,应该用带 **fencing token(单调递增的隔离令牌)**的方案——存储层校验 token,只接受更大的 token,拒绝「暂停后苏醒的旧持锁者」。
四、Redlock 作者的回应
Redis 作者 antirez 回应称:Redlock 在合理假设下是有效的,GC 停顿问题对任何分布式锁(包括 ZooKeeper)都存在,不是 Redlock 独有;fencing token 的思路很好但需要存储层配合。双方各有道理,这场争论成了分布式领域的经典案例。实践中的共识大致是:
- 一般业务(防重复、效率优化):普通 Redis 锁 / Redisson 就够,别过度设计。
- 强正确性要求:优先考虑带 fencing 的方案,或用 ZooKeeper/etcd 这类 CP 系统,或在存储层加乐观校验兜底,别把「绝对正确」全押在锁上。
记忆点:Redlock 用「N 个独立节点 + 多数派」解决主从丢锁,但防不住「持锁者自身 GC/暂停导致锁过期后仍以为持锁」。要绝对正确,需 fencing token 在存储层兜底。
五、要不要用 Redlock
- 成本:要维护 5 个独立 Redis 节点,运维成本高。
- 性能:每次加锁要访问 5 个节点,比单点慢。
- 收益:只在「主从丢锁」这个特定问题上有改善,且仍防不住时钟/暂停问题。
因此很多团队权衡后不用 Redlock:要么接受普通 Redisson 锁的小概率丢锁(配合业务幂等/兜底),要么直接上 ZooKeeper(CP,一致性更强)。Redlock 更多是面试考点和理论讨论。
六、常见误区与追问
这道题不能只背概念,要把「Redlock 算法」放回真实分布式系统里解释:谁发起、谁协调、状态如何变化、失败后怎么兜底,以及它和性能、可用性、一致性的取舍。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | Redlock 通过多个独立 Redis 节点加锁,要求多数节点成功且耗时小于有效期,降低单点 Redis 锁风险 | 不要停在名词解释 |
| 流程机制 | 生成唯一 value -> 依次向多个 Redis SET NX PX -> 统计成功节点数 -> 校验耗时和有效期 -> 成功进入临界区 -> 失败释放已获得锁 | 说明触发方、参与方、状态变化和兜底 |
| 工程取舍 | 5 个 Redis 节点中至少 3 个加锁成功,并且总耗时未超过 TTL,才认为加锁成功 | 分布式锁只能控制临界区进入,不能替代业务幂等和状态校验 |
Redlock 算法 面试拆解:
1. 生成唯一 value
2. 依次向多个 Redis SET NX PX
3. 统计成功节点数
4. 校验耗时和有效期
5. 成功进入临界区
6. 失败释放已获得锁
记忆钩子:先说为什么单机锁失效,再说明加锁、过期、续期、解锁、防误删和故障恢复;回答时要紧扣「Redlock 算法」这道题,不要把相邻概念混成一段泛泛的分布式套话。
- 误区:Redlock 能提供绝对强一致锁。 它仍受时钟漂移、网络分区和实现细节影响,适合降低风险但不是共识协议。
- 误区:Redis 主从复制就等于 Redlock。 Redlock 要求多个相互独立 master,不是一个主从集群。
- 误区:成功节点越多越不需要 TTL。 TTL 仍是故障释放锁的关键。
- 追问:为什么要多数派? 避免单个 Redis 故障或丢数据导致锁判断失效。
- 追问:Redlock 的争议点是什么? 在异步网络和时钟漂移下是否满足严格互斥存在争议。
- 追问:强一致锁更适合什么? 可考虑 ZooKeeper/etcd 这类基于共识的协调系统。
七、加强记忆
Redlock 用 N 个独立 Redis 节点(非主从)+ 多数派加锁(5 个拿到 3 个且总耗时 < 有效期才成功)来解决主从异步复制 + 故障切换导致的丢锁问题,原理同 Quorum 防脑裂。但 Kleppmann 质疑它依赖时间假设:GC 停顿/进程暂停会让持锁者锁过期后仍误以为持锁,多数派防不住,时钟漂移也影响判断。结论:效率型锁用普通 Redis 就够,正确性型锁要用 fencing token 或 ZooKeeper/etcd 兜底。Redlock 成本高、收益有限,实践中常被跳过。