当前位置: 首页 > ai >正文

Redisson分布式锁:看门狗机制与续期原理

文章目录

  • 前言
  • 一、分布式锁的基本概念
    • 1.1 什么是分布式锁
    • 1.2 为什么选择Redisson
  • 二、Redisson分布式锁的使用
    • 2.1 基本使用示例
    • 2.2 可重入锁示例
    • 2.3 看门狗机制的自动续期
  • 三、底层原理深度分析
    • 3.1 加锁原理
    • 3.2 解锁原理
    • 3.3 看门狗(WatchDog)机制
      • 3.3.1 看门狗的工作原理
      • 3.3.2 续期脚本
    • 3.4 可重入实现原理
    • 四、总结

前言

在微服务架构和分布式系统中,分布式锁是保证数据一致性的重要手段。Redis作为高性能的内存数据库,天然适合实现分布式锁。而Redisson作为Redis的Java客户端,不仅提供了完善的分布式锁实现,还引入了看门狗(WatchDog)机制来解决锁续期问题。

一、分布式锁的基本概念

1.1 什么是分布式锁

分布式锁是在分布式环境下,多个进程或线程对共享资源进行互斥访问的一种机制。它需要满足以下特性:

  • 互斥性:同一时刻只能有一个进程持有锁
  • 可重入性:同一线程可以多次获取同一把锁
  • 阻塞与非阻塞:获取不到锁时的处理策略
  • 容错性:具备自动释放锁的能力

1.2 为什么选择Redisson

相比于直接使用Redis命令实现分布式锁,Redisson提供了以下优势:

  • 自动续期:通过看门狗机制避免业务执行时间过长导致的锁自动释放
  • 可重入实现:支持同一线程多次获取同一把锁
  • 阻塞等待:提供tryLock等方法支持超时等待
  • Lua脚本:保证原子性操作

二、Redisson分布式锁的使用

2.1 基本使用示例

@Service
public class DistributedLockService {@Autowiredprivate RedissonClient redissonClient;public void processWithLock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);try {// 尝试获取锁,等待时间10秒,锁自动释放时间30秒boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);if (isLocked) {System.out.println("获取锁成功,开始处理业务逻辑");// 执行业务逻辑doBusinessLogic();System.out.println("业务逻辑处理完成");} else {System.out.println("获取锁失败");}} catch (InterruptedException e) {Thread.currentThread().interrupt();System.err.println("获取锁被中断");} finally {// 释放锁if (lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("锁已释放");}}}private void doBusinessLogic() {try {// 模拟业务处理时间Thread.sleep(5000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

2.2 可重入锁示例

public class ReentrantLockDemo {private final RedissonClient redissonClient;private final RLock lock;public ReentrantLockDemo(RedissonClient redissonClient) {this.redissonClient = redissonClient;this.lock = redissonClient.getLock("reentrant:lock");}public void method1() {lock.lock();try {System.out.println("执行方法1");method2(); // 可重入调用} finally {lock.unlock();}}public void method2() {lock.lock(); // 同一线程再次获取锁try {System.out.println("执行方法2");method3();} finally {lock.unlock();}}public void method3() {lock.lock(); // 同一线程第三次获取锁try {System.out.println("执行方法3");} finally {lock.unlock();}}
}

2.3 看门狗机制的自动续期

public class WatchDogDemo {private final RedissonClient redissonClient;public WatchDogDemo(RedissonClient redissonClient) {this.redissonClient = redissonClient;}public void longRunningTask() {RLock lock = redissonClient.getLock("watchdog:lock");try {// 不指定锁的过期时间,启用看门狗机制lock.lock();System.out.println("开始执行长时间任务");// 模拟长时间运行的任务(超过默认锁过期时间30秒)for (int i = 0; i < 10; i++) {Thread.sleep(10000); // 每次休眠10秒System.out.println("任务进行中... " + (i + 1) * 10 + "秒");}System.out.println("长时间任务执行完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}}
}

三、底层原理深度分析

3.1 加锁原理

Redisson使用Lua脚本来保证加锁操作的原子性,核心脚本如下:

-- 加锁脚本
if (redis.call('exists', KEYS[1]) == 0) thenredis.call('hset', KEYS[1], ARGV[2], 1);redis.call('pexpire', KEYS[1], ARGV[1]);return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) thenredis.call('hincrby', KEYS[1], ARGV[2], 1);redis.call('pexpire', KEYS[1], ARGV[1]);return nil;
end;
return redis.call('pttl', KEYS[1]);

这个脚本的执行逻辑:

  1. KEYS[1]:锁的名称
  2. ARGV[1]:锁的过期时间(毫秒)
  3. ARGV[2]:线程标识(UUID + 线程ID)

执行流程:

  • 如果锁不存在,创建锁并设置过期时间
  • 如果锁存在且是当前线程持有,重入计数加1
  • 否则返回锁的剩余存活时间

3.2 解锁原理

解锁同样使用Lua脚本保证原子性:

-- 解锁脚本
if (redis.call('exists', KEYS[1]) == 0) thenreturn 1;
end;
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) thenreturn nil;
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) thenredis.call('pexpire', KEYS[1], ARGV[2]);return 0;
elseredis.call('del', KEYS[1]);redis.call('publish', KEYS[2], ARGV[1]);return 1;
end;

解锁逻辑:

  • 锁不存在直接返回
  • 当前线程不持有锁返回null
  • 重入计数减1,如果大于0重新设置过期时间
  • 如果计数为0,删除锁并发布解锁消息

3.3 看门狗(WatchDog)机制

看门狗机制是Redisson的核心特性,解决了业务执行时间不确定导致的锁提前释放问题。

3.3.1 看门狗的工作原理

实现原理概览
看门狗机制本质上是一个 后台定时任务,它:

  1. 在成功获取锁后自动启动
  2. 每隔一段时间检查当前线程是否仍然持有锁
  3. 如果是,则向 Redis 发送命令延长锁的过期时间(TTL)
  4. 直到锁被显式释放(unlock())或客户端断开

3.3.2 续期脚本

-- 续期脚本
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) thenredis.call('pexpire', KEYS[1], ARGV[1]);return 1;
end;
return 0;

看门狗机制的关键点:

  1. 续期时机:每隔 lockLeaseTime/3 时间执行一次续期
  2. 续期条件:只有当前线程持有锁时才能续期成功
  3. 自动停止:锁释放时自动停止看门狗任务
  4. 默认时间:默认锁存活时间为30秒,续期间隔为10秒

3.4 可重入实现原理

Redisson使用Hash数据结构实现可重入:

锁的数据结构:
KEY: lock:mylock
VALUE: {"8743c9c0-0795-4907-87fd-6c719a6b4586:1": 3
}
  • KEY:锁的名称
  • Hash Field:客户端ID + 线程ID
  • Hash Value:重入次数

这种设计的优势:

  • 通过Hash结构存储线程标识和重入次数
  • 原子性操作保证数据一致性
  • 支持多线程并发访问不同的锁

四、总结

Redisson分布式锁通过以下几个关键机制实现了高可用、高性能的分布式锁方案:

  1. Lua脚本保证原子性:加锁、解锁、续期操作都通过Lua脚本实现原子性
  2. 看门狗机制解决续期问题:自动续期避免业务执行时间过长导致的锁丢失
  3. Hash结构实现可重入:使用Redis Hash存储线程信息和重入次数
  4. 发布订阅优化性能:通过Redis的pub/sub机制减少客户端轮询
http://www.xdnf.cn/news/20234.html

相关文章:

  • nginx安装部署(备忘)
  • ecplise配置maven插件
  • 【知识点讲解】稀疏注意力与LSH技术:从基础到前沿的完整指南
  • MHA高可用架构
  • 多线程(六) ~ 定时器与锁
  • 驱动开发系列71 - GLSL编译器实现 - 指令选择
  • python 逻辑运算练习题
  • HttpClient、OkHttp 和 WebClient
  • 贪心算法应用:交易费优化问题详解
  • OpenLayers常用控件 -- 章节七:测量工具控件教程
  • 《sklearn机器学习——聚类性能指标》Fowlkes-Mallows 得分
  • Java学习笔记二(类)
  • 【3D图像算法技术】如何在Blender中对复杂物体进行有效减面?
  • 【EXPLAIN详解:MySQL查询优化师的显微镜】
  • MacOS 使用 luarocks+wrk+luajit
  • Docker 本地开发环境搭建(MySQL5.7 + Redis7 + Nginx + 达梦8)- Windows11 版 2.0
  • Mac Intel 芯片 Docker 一键部署 Neo4j 最新版本教程
  • 【Android 消息机制】Handler
  • PDF教程|如何把想要的网页保存下来?
  • docker 推送仓库(含搭建、代理等)
  • 服务器线程高占用定位方法
  • 使用 Shell 脚本监控服务器 IOWait 并发送邮件告警
  • Python带状态生成器完全指南:从基础到高并发系统设计
  • C#实现导入CSV数据到List<T>的完整教程
  • 【基础-单选】用哪一种装饰器修饰的struct表示该结构体具有组件化能力?
  • Playwright携手MCP:AI智能体实现自主化UI回归测试
  • 第26节:GPU加速计算与Compute Shader探索
  • Homebrew执行brew install出现错误(homebrew-bottles)
  • Go语言后端开发面试实战:谢飞机的“硬核”面试之旅
  • CodeBuddy 辅助重构:去掉 800 行 if-else 的状态机改造