# Redis 中如何实现分布式锁?

6 min read
Table of Contents

Redis 中如何实现分布式锁?

Redis 分布式锁实现详解

【核心定义】

Redis 分布式锁是通过 Redis 的原子性操作和键值对存储特性,在分布式系统中实现互斥访问共享资源的一种协调机制。

【关键要点】

  1. SETNX + EXPIRE 基础方案

    • 使用 SETNX key value 尝试获取锁(key 存在则失败)
    • 成功后立即设置过期时间 EXPIRE key seconds 防止死锁
    • 缺陷:两个命令非原子操作,可能因客户端崩溃导致锁无过期时间
  2. SET 扩展命令(Redis 2.6.12+)

    • 单命令原子操作:SET key value NX EX seconds
    • NX 表示仅当 key 不存在时设置,EX 设置过期时间(秒)
    • 示例:SET lock:order123 uuid NX EX 30
  3. 唯一标识与释放验证

    • value 必须使用唯一标识(如 UUID + 线程ID)
    • 释放锁时先 GET 验证 value 匹配,再 DEL 删除(需 Lua 脚本保证原子性)
  4. 超时时间与续期机制

    • 过期时间需大于业务执行时间(通常 10-30 秒)
    • 复杂业务需实现「看门狗」自动续期(Redisson 方案)
  5. 集群环境与 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 0
end

逻辑拆解:

  • 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 依赖系统时钟,时钟跳跃可能导致:

  1. 锁提前过期(时钟向前跳)
  2. 锁超时未释放(时钟向后跳) 解决方案:使用单调时钟(monotonic clock)计算耗时

【关联/对比】

Redis 分布式锁 vs ZooKeeper 分布式锁

维度RedisZooKeeper
实现复杂度简单复杂(需处理临时节点、Watch)
性能高(内存操作)中等(需要持久化)
可靠性主从切换可能丢锁CP 模型,强一致
死锁处理依赖过期时间会话结束自动删除临时节点
适用场景高性能、允许偶尔失效强一致性要求高

Redis 单实例 vs 集群方案

  • 单实例:简单高效,但单点故障
  • 哨兵模式:自动故障转移,但主从切换时可能丢锁
  • 集群模式:数据分片,需使用 Redlock 等算法

『面试官追问』

常见追问问题:

  1. 如果业务执行时间超过锁过期时间怎么办?

    • 答:实现「看门狗」机制,后台线程定期检查并续期(Redisson 方案)
    • 或采用分段锁,将大任务拆分为多个小锁
  2. Redis 主从切换时如何保证锁不丢失?

    • 答:Redlock 算法在多个独立节点上获取锁,容忍少数节点故障
    • 或使用 Redis 的 WAIT 命令确保数据同步到从节点
  3. 如何实现可重入锁?

    • 答:value 中存储「客户端标识 + 重入次数」,加锁时次数+1,解锁时次数-1,归零才删除 key
  4. Redis 分布式锁是公平锁吗?

    • 答:默认不是公平锁,所有客户端同时争抢。可通过 Redis 列表实现排队机制模拟公平锁
  5. 锁已经设置了过期时间,为什么还需要唯一标识?

    • 答:防止误删其他客户端的锁(如上文 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 等完整实现,避免重复造轮子。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

Comments