面试题:说说 Redisson 分布式锁的原理?

Redisson 是一个基于 Redis 的 Java 客户端,它封装了分布式锁的实现,解决了传统 SETNX 等方法的局限性。其核心原理围绕 原子性安全性 和 自动续期 设计,以下是详细解析:


一、Redisson 分布式锁的核心机制

1. 加锁机制

  • 原子性加锁
    Redisson 使用 Lua 脚本 实现加锁操作,确保整个流程的原子性(避免分步执行导致的问题)。
    • 关键逻辑
      • KEYS[1]:锁的 key(如 myLock)。
      • ARGV[2]:客户端唯一标识(如 UUID + 线程 ID)。
      • ARGV[1]:锁的过期时间(如 30 秒)。
        if (redis.call('exists', KEYS[1]) == 0) then
            redis.call('hset', KEYS[1], ARGV[2], 1)
            redis.call('pexpire', KEYS[1], ARGV[1])
            return nil
        end
    • 作用
      • 如果锁不存在(exists == 0),则设置锁并绑定客户端标识,同时设置过期时间。
      • 如果锁已存在,则直接返回失败。
  • 重入锁
    Redisson 支持 可重入锁(Reentrant Lock)。
    • 同一线程多次加锁时,Redisson 会通过 hset 记录重入次数(例如 hset myLock uuid:threadId 2)。
    • 解锁时,需将重入次数减 1,直到为 0 时才真正释放锁。

2. 解锁机制

  • 原子性解锁
    Redisson 同样使用 Lua 脚本保证解锁的原子性
    • 逻辑
      • 验证当前客户端是否持有锁(hexists)。
      • 重入次数减 1,若为 0 则删除锁。
      • 防止误删:只有持有锁的客户端才能解锁。
        if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
            return nil
        end
        local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1)
        if (counter > 0) then
            redis.call('pexpire', KEYS[1], ARGV[2])
            return counter
        end
        redis.call('del', KEYS[1])
        return nil

3. 看门狗(Watch Dog)自动续期

  • 问题背景
    如果业务逻辑执行时间超过锁的过期时间,锁会自动释放,导致其他线程获取锁(出现并发问题)。
  • 解决方案
    Redisson 提供 看门狗机制,在锁未被释放时,自动延长锁的过期时间。
    • 流程
      1. 客户端加锁后,启动一个后台线程(看门狗)。
      2. 看门狗每隔一定时间(默认锁过期时间的 1/3)检查锁是否仍被当前线程持有。
      3. 如果持有,则续期锁的过期时间(例如从 30 秒重置为 30 秒)。
    • 优势
      • 避免因业务执行时间过长导致锁提前释放。
      • 不需要手动设置锁的超时时间(适用于不可预估执行时间的场景)。

4. 集群环境下的锁

  • Redis Cluster 支持
    Redisson 在 Redis Cluster 模式下通过 哈希槽(Hash Slot) 确定锁存储的节点。
    • 客户端根据锁 key 计算哈希槽,选择对应的主节点进行加锁。
    • 注意:Redisson 的分布式锁不依赖 Redis 的集群特性(如 Redlock 算法),而是通过单节点加锁实现,因此对网络分区敏感(需权衡一致性与可用性)。

二、Redisson 分布式锁的特性

特性实现方式优势
原子性使用 Lua 脚本封装加锁/解锁逻辑避免分步操作导致的竞态条件
安全性通过客户端唯一标识(UUID + 线程 ID)验证锁归属防止误删其他线程的锁
重入性使用 hset 记录重入次数支持同一线程多次加锁
自动续期看门狗线程定时续期避免因业务执行时间过长导致锁失效
高性能基于 Redis 单线程模型,减少网络开销适用于高并发场景

三、典型应用场景

  1. 高并发秒杀
    • 多个服务实例争夺库存资源,通过 Redisson 锁控制并发访问。
  2. 分布式任务调度
    • 确保同一时刻只有一个实例执行任务(如定时清理日志)。
  3. 接口幂等性控制
    • 防止重复提交订单或重复扣款(结合唯一业务 ID 加锁)。

四、Redisson 与传统方案的对比

对比维度Redisson传统 SETNX + EXPIRE
原子性Lua 脚本保障原子性分步操作(SETNX + EXPIRE)存在竞态条件
锁误删通过客户端标识验证,避免误删直接删除 key,可能误删其他线程的锁
重入性支持重入不支持
自动续期看门狗自动延长锁过期时间需手动续期
代码复杂度封装简洁,API 易用需自行处理 Lua 脚本、异常捕获等

五、总结

Redisson 分布式锁的原理核心在于:

  1. 通过 Lua 脚本实现原子性加锁/解锁,避免竞态条件。
  2. 结合客户端标识和重入计数,确保安全性和灵活性。
  3. 看门狗机制自动续期,适应长时业务场景。
  4. 简化开发复杂度,提供开箱即用的分布式锁功能。

其设计平衡了性能、安全性和易用性,是分布式系统中控制资源竞争的实用方案。

THE END
喜欢就支持一下吧
点赞8 分享