2025-08-28 11:43

如何利用Redis实现一个分布式锁

王姐姐

大数据

(51)

(0)

收藏

利用 Redis 实现分布式锁,最常用且可靠的方式是使用 SETNX + EXPIRE 或更优的原子命令 SET 命令的 NX 和 EX 选项,并结合合理设计避免常见问题。


✅ 一、基本实现(Redis 2.6.12+ 推荐写法)

SET lock_key unique_value NX EX 30
  • NX:键不存在时才设置(类似 SETNX)

  • EX 30:设置过期时间为 30 秒(防止死锁)

  • unique_value:当前线程唯一标识(如 UUID),用于安全释放锁

✅ 原子操作,避免 SETNX 和 EXPIRE 分开执行的并发问题。


✅ 二、加锁(Lock)

SET resource_name unique_value NX EX 30
  • 成功:返回 OK,获得锁

  • 失败:返回 (nil),锁已被占用


✅ 三、释放锁(Unlock)——必须校验唯一值

-- 使用 Lua 脚本保证原子性
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

❗ 必须用 Lua 脚本:防止检查和删除之间被其他线程抢占,造成误删。


⚠️ 四、要注意的关键问题

问题

说明

解决方案

1. 死锁(未释放锁)

线程崩溃或异常退出,锁未释放

设置 自动过期时间(EX),如 30 秒

2. 锁过期,业务未执行完

锁提前过期,多个线程同时持有锁

使用 看门狗(Watchdog)机制:Redisson 等客户端支持自动续期

3. 误删其他线程的锁

释放锁时未校验持有者

释放时比较 unique_value,用 Lua 脚本原子删除

4. 主从切换导致锁失效

主节点未同步到从节点就宕机,从节点提升为主,锁丢失

使用 Redlock 算法(多个独立 Redis 实例),但性能低、争议大
或使用 ZooKeeper / Etcd 等 CP 系统实现强一致锁

5. 时钟漂移

多个 Redis 实例间时间不一致,影响 Redlock

尽量避免使用 Redlock,或严格同步系统时间


✅ 五、最佳实践建议

  1. 使用成熟的客户端库:如 Redisson(Java)、Lettuce 等,内置分布式锁、看门狗、自动续期。

  2. 设置合理的过期时间:基于业务执行时间评估,避免太短或太长。

  3. 唯一值 + Lua 脚本释放锁:防止误删。

  4. 考虑高可用场景:若对一致性要求极高,建议使用 ZooKeeper 等 CP 系统。

  5. 避免长时间持有锁:锁粒度要小,尽快释放。


✅ 总结

Redis 分布式锁核心:

SET key unique_value NX EX timeout + Lua 脚本释放 + 过期时间 + 唯一标识

⚠️ 虽然简单高效,但要注意锁过期、误删、主从不一致等问题,不适合强一致性场景
✅ 在大多数高并发、最终一致的场景下(如秒杀、库存扣减),Redis 锁是高效实用的选择。


0条评论

点击登录参与评论