day39 Redisson可重入锁,锁重试,WatchDog与MultiLock

1. 今天做了什么

  • 学习使用成熟的 Redisson 解决自定义 Redis 分布式锁目前存在的问题:
    • 不可重入;
    • 不可重试;
    • 超时释放;
    • 主从一致性问题。
  • 完成 Redisson 的基本使用:
    1. 引入依赖;
    2. 通过配置类进行配置;
    3. 获取锁对象;
    4. 尝试获取锁并释放锁。
  • 学习 Redisson 可重入锁、锁重试、WatchDog 自动续期和 MultiLock 的实现思路。

2. 核心知识点

  • Redisson 可重入锁:

    • 采用 Hash 存储结构:key 是锁的 key,field 是线程标识,value 是重入次数。
    • 获取锁:
      1. 判断 key 是否存在;
      2. 不存在则获取锁,并设置有效期;
      3. 存在则判断线程标识与自己是否一致;
      4. 一致则将重入次数加 1,并更新过期时间;
      5. 不一致则说明锁被其他线程持有,获取失败。
    • 释放锁:
      1. 判断 key 是否存在;
      2. 不存在则说明锁已经释放,结束;
      3. 存在则判断线程标识是否一致;
      4. 不一致则说明锁已经释放并被其他线程持有,结束;
      5. 一致则将重入次数减 1;
      6. 重入次数为 0 时删除 key;
      7. 重入次数不为 0,说明本次释放不是最外层,仍有业务逻辑,更新过期时间。
    • 获取锁与释放锁均使用 Lua 脚本,以保证原子性。
  • Redisson 锁重试:

    1. 执行获取锁的 Lua 脚本;成功返回 null,失败返回锁的剩余过期时间;
    2. 返回 null 说明获取成功,流程结束;
    3. 获取失败则进入等待流程;
    4. 等待流程维护剩余等待时间,一旦小于等于 0,直接结束,不再等待;
    5. 剩余等待时间大于 0 时,订阅并等待锁释放信号;
    6. 等待超时则结束,未超时则再次尝试获取锁。
  • Redisson 解决超时释放问题:

    • 未设置过期时间时会启动 WatchDog;
    • WatchDog 使用自动续约的定时任务,每 10 秒续约一次,避免业务执行期间锁超时;
    • 成功释放锁后取消 WatchDog。

  • Redisson MultiLock:
    • 搭建多个独立的 Redis 节点;
    • 所有节点的锁都获取成功,整体获取锁才成功;
    • 如果超时或有节点获取失败,则释放已经获取的锁;
    • 它用于处理主从一致性问题导致的锁失效:主节点宕机时,如果锁 key 尚未同步,从节点接替主节点会导致 key 丢失,其他线程可能获取锁;
    • 多个独立节点要求全部加锁成功,某个节点宕机时,其他线程无法获取完整的锁。
  • MultiLock 的缺点:一个节点宕机会导致所有进程都无法获取完整的锁。

3. 深度思考

  • 自定义 Redis 分布式锁可以逐步解决互斥、误删和原子性问题,但可重入、重试、自动续期及主从一致性处理更复杂,适合直接采用 Redisson 这类成熟方案。

4. 踩过的坑

5. 遗留问题 / 想不通