好的,我给你整理一下Redis实现分布式锁的七种常见方案,并分析它们的原理、优缺点和适用场景。
Redis 分布式锁 7 种实现方案
1. SETNX + EXPIRE(基本型)
原理
- 使用
SETNX key value
尝试获取锁,成功则返回 1。 - 再用
EXPIRE key timeout
设置过期时间,防止死锁。
优点
- 实现简单。
缺点
- 非原子操作:SETNX 和 EXPIRE 不是原子操作,可能出现死锁。
- 如果在 SETNX 后还没执行 EXPIRE 就宕机,锁不会释放。
改进
- 用 Lua 脚本保证原子性(见方案 2)。
2. SETNX + EXPIRE(原子型 / Lua 脚本)
原理
- 使用 Lua 脚本将 SETNX + EXPIRE 原子化:
if redis.call("setnx",KEYS[1],ARGV[1]) == 1 then
return redis.call("expire",KEYS[1],ARGV[2])
else
return 0
end
- 或使用 Redis 2.6+ 的
SET key value NX PX milliseconds
命令:
SET lock_key unique_value NX PX 3000
优点
- 原子操作,避免死锁。
- 支持自动过期。
缺点
- 仍可能出现锁释放误删,需要 value 唯一标识。
3. 带唯一标识的锁(安全释放)
原理
- 给锁的 value 设置唯一标识(UUID、线程ID)。
- 释放锁时,用 Lua 脚本判断 value 是否匹配,防止误删:
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
优点
- 安全释放锁,避免释放别人的锁。
缺点
- 单机 Redis,如果 Redis 宕机,锁会丢失。
4. Redlock(分布式安全锁)
原理
- Redis 官方推荐算法。
- 在 多个独立 Redis 实例(N=5) 上获取锁。
- 必须在 大多数节点(>=3) 成功获取锁才能认为锁成功。
- 设置有效期,超时自动释放。
优点
- 高可用、安全性高。
- 避免单机 Redis 宕机导致锁失效。
缺点
- 算法复杂,实现难度高。
- 在网络分区情况下仍有争议。
5. 延迟重试 + 自旋锁
原理
- 获取锁失败时,不立即失败,而是:
- 自旋重试(忙等)
- 或 sleep 一段时间后重试
优点
- 减少锁获取失败带来的业务异常。
- 简单实现“阻塞式锁”。
缺点
- 自旋消耗 CPU。
- 需要合理设置重试间隔和超时时间。
6. 看门狗机制(Redisson实现)
原理
- Redisson 提供自动续期机制(watchdog)。
- 锁持有者在锁快到期时自动延长过期时间。
优点
- 解决业务执行时间长导致锁过期的问题。
- 使用简单,适合业务不确定耗时场景。
缺点
- 依赖 Redisson 客户端。
- 会增加 Redis 额外心跳开销。
7. 公平锁 / 信号量型锁
原理
- 利用 Redis 列表(List) 实现公平队列:
- 请求锁时将请求加入队列。
- 轮到自己时获取锁。
- 可以扩展为 信号量,允许同时 N 个线程持锁。
优点
- 避免“饥饿”现象,公平获取锁。
- 可控制并发量(信号量模式)。
缺点
- 实现复杂,需要自己维护队列和锁释放逻辑。
- Redis 内存占用稍大。
总结对比表
方案 | 是否分布式 | 是否安全 | 是否阻塞/等待 | 适用场景 |
---|---|---|---|---|
1. SETNX+EXPIRE | ❌ 单机 | ❌ 可能死锁 | ❌ 非阻塞 | 简单场景 |
2. SETNX+EXPIRE Lua | ❌ 单机 | ✅ 原子 | ❌ 非阻塞 | 简单场景,防止死锁 |
3. 带唯一标识 | ❌ 单机 | ✅ 安全释放 | ❌ 非阻塞 | 单机安全锁 |
4. Redlock | ✅ 多机 | ✅ 高安全 | ❌ 可阻塞 | 分布式高可用锁 |
5. 自旋锁 | ✅ / ❌ | ❌ | ✅ 阻塞 | 高并发重试 |
6. 看门狗(Redisson) | ✅ 多机 | ✅ 自动续期 | ✅ 阻塞 | 长耗时任务 |
7. 公平锁 / 信号量 | ✅ 多机 | ✅ | ✅ 阻塞 | 控制并发量,公平获取 |
如果你需要,我可以帮你画一张Redis分布式锁方案对比图,直观展示 复杂度、分布式特性、安全性,非常适合PPT或技术分享。
你希望我画吗?
发表回复