# Redis 中如何实现分布式锁?
6 min read
Table of Contents
Redis 中如何实现分布式锁?
Redis 分布式锁实现详解
【核心定义】
Redis 分布式锁是通过 Redis 的原子性操作和键值对存储特性,在分布式系统中实现互斥访问共享资源的一种协调机制。
【关键要点】
-
SETNX + EXPIRE 基础方案
- 使用
SETNX key value尝试获取锁(key 存在则失败) - 成功后立即设置过期时间
EXPIRE key seconds防止死锁 - 缺陷:两个命令非原子操作,可能因客户端崩溃导致锁无过期时间
- 使用
-
SET 扩展命令(Redis 2.6.12+)
- 单命令原子操作:
SET key value NX EX seconds - NX 表示仅当 key 不存在时设置,EX 设置过期时间(秒)
- 示例:
SET lock:order123 uuid NX EX 30
- 单命令原子操作:
-
唯一标识与释放验证
- value 必须使用唯一标识(如 UUID + 线程ID)
- 释放锁时先 GET 验证 value 匹配,再 DEL 删除(需 Lua 脚本保证原子性)
-
超时时间与续期机制
- 过期时间需大于业务执行时间(通常 10-30 秒)
- 复杂业务需实现「看门狗」自动续期(Redisson 方案)
-
集群环境与 Redlock 算法
- 主从切换可能导致锁失效
- Redlock:在 N 个独立 Redis 节点上获取多数锁(N/2+1)才算成功
【深度推导/细节】
锁释放的原子性问题
-- Lua 脚本保证 GET + DEL 的原子性if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1])else return 0end逻辑拆解:
- Step 1:客户端 A 获取锁成功(value=uuid_A)
- Step 2:业务执行时间过长,锁自动过期释放
- Step 3:客户端 B 获取相同锁成功(value=uuid_B)
- Step 4:客户端 A 执行完成,直接 DEL 会误删 B 的锁
- Step 5:使用 Lua 脚本验证 value 匹配,避免误删
临界点设计原理
- 过期时间 30 秒:平衡业务执行时间与系统风险
- 太短:业务未完成锁已释放,导致并发问题
- 太长:客户端崩溃后资源长时间不可用
- Redlock 的 N=5:奇数节点确保多数决,容忍最多 (N-1)/2 个节点故障
时钟跳跃风险
Redlock 依赖系统时钟,时钟跳跃可能导致:
- 锁提前过期(时钟向前跳)
- 锁超时未释放(时钟向后跳) 解决方案:使用单调时钟(monotonic clock)计算耗时
【关联/对比】
Redis 分布式锁 vs ZooKeeper 分布式锁
| 维度 | Redis | ZooKeeper |
|---|---|---|
| 实现复杂度 | 简单 | 复杂(需处理临时节点、Watch) |
| 性能 | 高(内存操作) | 中等(需要持久化) |
| 可靠性 | 主从切换可能丢锁 | CP 模型,强一致 |
| 死锁处理 | 依赖过期时间 | 会话结束自动删除临时节点 |
| 适用场景 | 高性能、允许偶尔失效 | 强一致性要求高 |
Redis 单实例 vs 集群方案
- 单实例:简单高效,但单点故障
- 哨兵模式:自动故障转移,但主从切换时可能丢锁
- 集群模式:数据分片,需使用 Redlock 等算法
『面试官追问』
常见追问问题:
-
如果业务执行时间超过锁过期时间怎么办?
- 答:实现「看门狗」机制,后台线程定期检查并续期(Redisson 方案)
- 或采用分段锁,将大任务拆分为多个小锁
-
Redis 主从切换时如何保证锁不丢失?
- 答:Redlock 算法在多个独立节点上获取锁,容忍少数节点故障
- 或使用 Redis 的 WAIT 命令确保数据同步到从节点
-
如何实现可重入锁?
- 答:value 中存储「客户端标识 + 重入次数」,加锁时次数+1,解锁时次数-1,归零才删除 key
-
Redis 分布式锁是公平锁吗?
- 答:默认不是公平锁,所有客户端同时争抢。可通过 Redis 列表实现排队机制模拟公平锁
-
锁已经设置了过期时间,为什么还需要唯一标识?
- 答:防止误删其他客户端的锁(如上文 Step 4-5 的场景)
性能优化要点:
- 锁粒度尽可能细(按业务ID分锁)
- 非必要不使用 Redlock(性能损耗约降低一半)
- 设置合理的重试策略(指数退避算法)
版本差异:
- Redis 2.6.12 前:需使用 SETNX + EXPIRE 组合(非原子)
- Redis 2.6.12+:推荐使用 SET NX EX 单命令
- Redis 6.0+:支持 ACL,可在锁命令上设置更细粒度的权限控制
总结:Redis 分布式锁的核心在于「原子操作 + 唯一标识 + 过期时间」三要素,生产环境推荐使用 Redisson 客户端,它已封装了可重入锁、看门狗、Redlock 等完整实现,避免重复造轮子。