Redis 分布式锁实现方案与常见死锁问题排查

作者:袖梨 2026-07-08
Redis分布式锁需闭环管理生命周期:加锁用SET key value NX EX seconds保证原子性,value为唯一标识;解锁用Lua脚本校验再删;设合理过期时间并启用Watch Dog续期;高可用依赖哨兵/集群,强一致场景用RedLock。

Redis 分布式锁不是“加个 SETNX 就完事”,真正落地时,死锁、误删锁、锁提前释放等问题频发。核心不在命令本身,而在锁的生命周期管理是否闭环——从加锁原子性、持有身份校验、超时控制,到故障恢复和集群一致性,缺一不可。

加锁必须带唯一标识 + 自动过期

只用 SETNX 或分开执行 SET + EXPIRE 是危险的:前者不支持设置过期时间,后者非原子,可能键设成功但过期没设上,导致永久锁死。

  • 正确写法是使用 SET key value NX EX seconds,一步完成“存在则失败 + 值写入 + 过期设定”
  • value 必须是全局唯一标识(如 UUID + 线程 ID),后续释放锁时靠它验证归属,避免误删
  • 过期时间不能拍脑袋定,需结合业务最长耗时 + 安全冗余(建议至少比 P99 耗时多 2–3 倍)

解锁必须原子校验再删除

先 GET 再 DEL 是典型并发漏洞:GET 到自己的 value,刚要 DEL 时锁已过期,别人抢锁成功,你 DEL 的其实是别人的锁。

  • 必须用 Lua 脚本封装校验与删除逻辑,保证“读-判-删”不可分割
  • 脚本示例:if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
  • 客户端调用该脚本时,传入锁 key 和自己加锁时写的 value,返回 1 表示删除成功,0 表示锁已被他人持有或不存在

业务执行中锁不能“静默失效”

锁过期时间短于业务实际耗时,会导致锁自动释放后别人加锁成功,原线程继续执行并释放新锁——数据错乱由此产生。

  • 手动实现 Watch Dog:加锁后起守护线程,每 过期时间 / 3 检查一次锁归属,若仍属自身则用 EXPIRE 重置过期时间
  • 推荐直接用 Redisson:内置看门狗机制,默认 30 秒锁过期,每 10 秒自动续期,业务结束才停续期
  • 注意:续期操作本身也需校验锁归属,防止主从切换后向旧主续期(Redisson 已处理该细节)

高可用不能只靠单实例

单点 Redis 宕机,所有锁服务瘫痪;主从异步复制下主节点崩溃未同步锁,从节点升主后锁丢失——两种情况都会引发并发失控。

  • 基础保障:部署哨兵模式或 Redis Cluster,确保服务不中断
  • 强一致性场景:采用 RedLock 算法,向 ≥3 个物理隔离的 Redis 实例加锁,多数(N/2+1)成功才算加锁成功
  • 降级策略:锁获取失败时,可走本地限流、排队队列或业务层幂等兜底,避免雪崩

相关文章

精彩推荐