Redis缓存击穿时,分布式锁导致死锁,如何有效解除?
- 内容介绍
- 文章标签
- 相关推荐
本文共计575个文字,预计阅读时间需要3分钟。
基本原因在于锁的释放逻辑和持有者不匹配,或者锁未设置过期时间。例如,使用SETNX和EXPIRE两步操作时,如果SETNX成功但后续过程崩溃或网络中断,EXPIRE将不会执行,导致锁永久存在于Redis中。另外,业务代码异常未执行DEL操作,也会导致锁残留。
加锁必须带原子性+自动过期
避免手动分两步设锁和过期,直接用原子命令:
-
SET key value EX seconds NX(推荐)—— 一条命令完成「不存在才设值 + 设置过期」 - 不要用
SETNX后再EXPIRE,这两步非原子,中间出错就留孤儿锁 - value 必须是唯一标识(如 UUID 或服务实例 ID),不能写死成
"1",否则释放时无法校验归属
释放锁必须校验 ownership
只靠 DEL key 是危险的:A 拿到锁,B 在 A 还没释放时误删了它,后续并发就失控了。正确做法是用 Lua 脚本做原子校验:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
这个脚本确保只有持锁者才能删锁。对应 Java 工具类中 releaseLock(String key, String value) 的实现必须走这个逻辑,不能简单调 jedis.del(key)。
本文共计575个文字,预计阅读时间需要3分钟。
基本原因在于锁的释放逻辑和持有者不匹配,或者锁未设置过期时间。例如,使用SETNX和EXPIRE两步操作时,如果SETNX成功但后续过程崩溃或网络中断,EXPIRE将不会执行,导致锁永久存在于Redis中。另外,业务代码异常未执行DEL操作,也会导致锁残留。
加锁必须带原子性+自动过期
避免手动分两步设锁和过期,直接用原子命令:
-
SET key value EX seconds NX(推荐)—— 一条命令完成「不存在才设值 + 设置过期」 - 不要用
SETNX后再EXPIRE,这两步非原子,中间出错就留孤儿锁 - value 必须是唯一标识(如 UUID 或服务实例 ID),不能写死成
"1",否则释放时无法校验归属
释放锁必须校验 ownership
只靠 DEL key 是危险的:A 拿到锁,B 在 A 还没释放时误删了它,后续并发就失控了。正确做法是用 Lua 脚本做原子校验:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
这个脚本确保只有持锁者才能删锁。对应 Java 工具类中 releaseLock(String key, String value) 的实现必须走这个逻辑,不能简单调 jedis.del(key)。

