Redisson Watchdog实现原理与源码解析:分布式锁的自动续期机制
引言
在分布式系统中,Redis分布式锁是解决资源竞争问题的常用方案。然而,当持有锁的客户端因GC、网络延迟或处理时间过长导致锁过期时,可能引发数据一致性问题。Redisson的Watchdog(看门狗)机制通过自动续期解决了这一痛点。本文将深入分析其实现原理,结合源码揭示其工作机制。
一、Watchdog的核心原理
1.1 什么是Watchdog?
Watchdog是Redisson客户端的一个后台线程,用于监控并自动续期分布式锁。当客户端获取锁时未显式指定leaseTime
(锁持有时间),Watchdog会启动,定期(默认每10秒)检查锁状态并延长锁的过期时间,避免业务未完成时锁提前释放。
1.2 核心机制
-
锁续期条件:仅当未指定
leaseTime
时生效。 -
续期规则:默认锁超时时间为30秒,每次续期重置为30秒。
-
续期间隔:超时时间的1/3(即10秒)。
-
自动释放:客户端宕机或进程退出时,Watchdog线程终止,锁超时后自动释放,避免死锁。
二、源码分析:从加锁到续期
2.1 关键类与入口
Redisson的分布式锁实现位于RedissonLock
类中。核心方法为:
// 获取锁入口
void lock(long leaseTime, TimeUnit unit);
2.2 锁获取与Watchdog启动
当leaseTime
未设置(默认为-1)时,触发Watchdog初始化:
// RedissonLock.java
public void lock() {try {lock(-1, null, false);} // ...
}private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {long threadId = Thread.currentThread().getId();Long ttl = this.tryAcquire(-1L, leaseTime, unit, threadId);if (ttl != null) {CompletableFuture<RedissonLockEntry> future = this.subscribe(threadId);this.pubSub.timeout(future);RedissonLockEntry entry;if (interruptibly) {entry = (RedissonLockEntry)this.commandExecutor.getInterrupted(future);} else {entry = (RedissonLockEntry)this.commandExecutor.get(future);}try {while(true) {ttl = this.tryAcquire(-1L, leaseTime, unit, threadId);if (ttl == null) {return;}if (ttl >= 0L) {try {entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);} catch (InterruptedException var14) {InterruptedException e = var14;if (interruptibly) {throw e;}entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);}} else if (interruptibly) {entry.getLatch().acquire();} else {entry.getLatch().acquireUninterruptibly();}}} finally {this.unsubscribe(entry, threadId);}}}
2.3 续期任务调度
scheduleExpirationRenewal()
启动定时任务:
// RedissonBaseLock.java
protected void scheduleExpirationRenewal(long threadId) {ExpirationEntry entry = new ExpirationEntry();ExpirationEntry oldEntry = (ExpirationEntry)EXPIRATION_RENEWAL_MAP.putIfAbsent(this.getEntryName(), entry);if (oldEntry != null) {oldEntry.addThreadId(threadId);} else {entry.addThreadId(threadId);try {this.renewExpiration();} finally {if (Thread.currentThread().isInterrupted()) {this.cancelExpirationRenewal(threadId);}}}}private void renewExpiration() {ExpirationEntry ee = (ExpirationEntry)EXPIRATION_RENEWAL_MAP.get(this.getEntryName());if (ee != null) {Timeout task = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {public void run(Timeout timeout) throws Exception {ExpirationEntry ent = (ExpirationEntry)RedissonBaseLock.EXPIRATION_RENEWAL_MAP.get(RedissonBaseLock.this.getEntryName());if (ent != null) {Long threadId = ent.getFirstThreadId();if (threadId != null) {CompletionStage<Boolean> future = RedissonBaseLock.this.renewExpirationAsync(threadId);future.whenComplete((res, e) -> {if (e != null) {RedissonBaseLock.log.error("Can't update lock " + RedissonBaseLock.this.getRawName() + " expiration", e);RedissonBaseLock.EXPIRATION_RENEWAL_MAP.remove(RedissonBaseLock.this.getEntryName());} else {if (res) {RedissonBaseLock.this.renewExpiration();} else {RedissonBaseLock.this.cancelExpirationRenewal((Long)null);}}});}}}}, this.internalLockLeaseTime / 3L, TimeUnit.MILLISECONDS);ee.setTimeout(task);}}
2.4 续期操作实现
renewExpirationAsync()
通过Lua脚本延长锁的过期时间:
// RedissonBaseLock.javaprotected CompletionStage<Boolean> renewExpirationAsync(long threadId) {return this.evalWriteAsync(this.getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) " +"then redis.call('pexpire', KEYS[1], " +"ARGV[1]); return 1; " +"end; return 0;", Collections.singletonList(this.getRawName()), this.internalLockLeaseTime, this.getLockName(threadId));}
-
Lua脚本逻辑:检查锁是否存在,若存在则重置过期时间为30秒(
internalLockLeaseTime
)。
三、Watchdog的生命周期
3.1 启动时机
-
锁获取成功:未指定
leaseTime
时触发。 -
锁重入:同一线程重复获取锁时不会重复启动。
3.2 停止条件
-
锁释放:调用
unlock()
时清理续期任务。 -
节点宕机:客户端进程终止,定时任务自动取消。
四、最佳实践与注意事项
4.1 正确配置参数
-
锁超时时间:通过
Config.lockWatchdogTimeout
调整(默认30秒)。 -
避免设置leaseTime:显式设置
leaseTime
会导致Watchdog失效。
4.2 避免陷阱
-
锁竞争与超时:确保业务执行时间小于锁超时时间。
-
网络分区风险:Redis集群脑裂可能导致锁失效,需配合Redlock算法使用。
五、总结
Redisson的Watchdog机制通过后台定时任务和Lua脚本的原子操作,实现了分布式锁的自动续期,解决了长任务场景下的锁超时问题。理解其源码逻辑有助于在实际开发中规避潜在风险,合理设计分布式锁的使用策略。
附录:Redisson版本
本文基于Redisson 3.17.7版本源码分析,不同版本实现可能略有差异。
希望这篇文章能帮助您深入理解Redisson的Watchdog机制。如有疑问,欢迎在评论区交流!
相关文章:
Redisson Watchdog实现原理与源码解析:分布式锁的自动续期机制
引言 在分布式系统中,Redis分布式锁是解决资源竞争问题的常用方案。然而,当持有锁的客户端因GC、网络延迟或处理时间过长导致锁过期时,可能引发数据一致性问题。Redisson的Watchdog(看门狗)机制通过自动续期解决了这一…...
在C#串口通信中,一发一收的场景,如何处理不同功能码的帧数据比较合理,代码结构好
在 C# 串口通信的一发一收场景里,处理不同功能码的帧数据可采用以下合理的代码结构,它能让代码更具可读性、可维护性和可扩展性。 实现思路 定义帧结构:创建一个类来表示通信帧,其中包含功能码、数据等信息。功能码处理逻辑&…...
easypoi 实现word模板导出
特此非常致谢:easypoi实现word模板 基础的可以参考上文; 但是我的需求有一点点不一样。 这是我的模板:就是我的t.imgs 是个list 但是很难过的是easy poi 我弄了一天,我都没有弄出来嵌套list循环怎么输出显示,更难过…...
集结号海螺捕鱼服务器调度与房间分配机制详解:六
本篇围绕服务器调度核心逻辑进行剖析,重点讲解用户连接过程、房间分配机制、服务端并发策略及常见性能瓶颈优化。适用于具备中高级 C 后端开发经验的读者,覆盖网络会话池、逻辑服调度器与房间生命周期管理等关键模块。 一、服务器结构概览 整体系统采用…...
opencv--图像滤波
图像滤波 含义 方法 噪声是怎么产生的 线性滤波 概念 利用窗口对图像中的像素进行加权求和的滤波方式。 图像来源于小虎教程。 图像的滤波是二维滤波的过程。 滤波器窗口: 滤波器窗口(也称为卷积核或模板)是一个小的矩阵(通常为…...
uniapp返回上一页接口数据更新了,页面未更新
注意:不是组件套组件可以不使用setTimeout延时 返回上一页一般会走onshow,但是接口更新了页面未更新 onShow(() > {// 切换城市后重新调用数据if (areaId.value) {const timer setTimeout(async () > {timer && clearTimeout(timer);…...
redis 使用 Docker 部署 简单的Redis 集群(包括哨兵机制)
目录 环境准备 步骤 1:创建 Docker Compose 配置文件 步骤 2:创建配置文件 主节点配置文件 (redis.conf) 从节点配置文件 (slave.conf) 哨兵配置文件 (sentinel.conf) 步骤 3:启动 Redis 集群 步骤 4:验证集群状态 1. 检…...
私有知识库 Coco AI 实战(三):摄入 Elasticsearch 官方文档
相信经常使用 Elasticsearch 的小伙伴,难免要到 ES 官网查找资料,文档内容多难以查找不说,还有很多个版本,加上各种生态工具如 Filebeat、Logstash 头就更大了。今天我来介绍如何使用 Coco AI 快速搜索 Elasticsearch 官方文档。在…...
12-DevOps-Gitlab托管Jenkinsfile
前面通过执行脚本的方式,完成了pipline流水线的构建。脚本是保存在Jenkins中的,这种方式不利于迁移,也不利于查找脚本的历史变更信息。 通过把脚本放到GitLab中,然后在Jenkins中引用的方式来解决上述的问题。 创建Jenkinsfile文件…...
CSS3 基础(边框效果)
一、边框效果 属性功能示例值说明border-radius创建圆角border-radius: 20px;设置元素的圆角半径,支持像素(px)或百分比(%)。值为 50% 时可变为圆形。box-shadow添加阴影box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.5)…...
使用 VSCode 编写 Markdown 文件
目录 一、安装 Markdown 插件二、新建 Markdown 文档三、Markdown 基本语法目录和标题文本样式列表图片链接代码表格注脚与注释符号表情 四、将 Markdown 文档导出为 PDF 一、安装 Markdown 插件 参考文章:【[Markdown] 使用vscode开始Markdown写作之旅】 打开 VSco…...
搭建 Stable Diffusion 图像生成系统并通过 Ngrok 暴露到公网(实现本地系统网络访问)——项目记录
目录 📚 背景与需求 📝 需求明确 🔑 核心功能 🌍 网络优化 🛠️ 方案确认 ⚙️ 技术栈 📈 实现流程(Flask端口Ngrok注册authtoken) 🎯 优化目标 🔍 实…...
伺服器用什么语言开发呢?做什么用什么?
最近因为要评估帮合作对象做连接我们工具的语言翻译器,所以顺便做了一个小范围的调查,看看那些语言是应该在我们优先制作翻译器的部分,当然,各种语言在伺服器开发中其实各有拥护者,而选择也很常受到应用场景、产业特性…...
实现SpringBoot底层机制【Tomcat启动分析+Spring容器初始化+Tomcat 如何关联 Spring容器】
下载地址: https://download.csdn.net/download/2401_83418369/90675207 一、搭建环境 创建新项目 在pom.xml文件中导入依赖 (一定要刷新Maven)排除内嵌的Tomcat,引入自己指定的Tomcat <?xml version"1.0" enco…...
spark—kafka
消息队列与Kafka介绍 消息队列模式: 点对点模式和发布订阅模式。Kafka主要使用发布订阅模式。 Kafka角色: 包括broker、topic、分区、生产者、消费者、消费者组、副本、leader和follower 术语 解释 Broker 安装了kafka的节点 Topic 每条发…...
【AI 加持下的 Python 编程实战 2_09】DIY 拓展:从扫雷小游戏开发再探问题分解与 AI 代码调试能力(上)
DIY 拓展:从扫雷小游戏开发再探问题分解与 AI 代码调试能力(上) 1 起因 最近在看去年刚出了第 2 版《Learn AI-assisted Python Programming》,梳理完 第七章 的知识点后,总感觉这一章的话题很好——问题分解能力的培…...
【JVS更新日志】物联网、智能BI、智能APS 4.23更新说明!
项目介绍 JVS是企业级数字化服务构建的基础脚手架,主要解决企业信息化项目交付难、实施效率低、开发成本高的问题,采用微服务配置化的方式,提供了低代码数据分析物联网的核心能力产品,并构建了协同办公、企业常用的管理工具等&…...
品融电商:领航食品类目全域代运营,打造品牌增长新引擎
品融电商:领航食品类目全域代运营,打造品牌增长新引擎 在竞争激烈的电商市场中,食品类目因其高频消费与强复购属性,成为品牌必争之地。然而,行业同质化严重、用户心智难突破、流量成本攀升等痛点,让许多食…...
非关系型数据库 八股文 Redis相关 缓存雪崩 击穿 穿透
目录 图 缓存雪崩 大量数据同时过期解决方案 也有可能是 Redis 挂了 故障 缓存击穿 用互斥锁解决 热点数据永远不过期 缓存穿透 重点 可能的原因 限制 请求的 访问 缓存空值或者默认值 布隆过滤器(重要) 总结 参考资料 图 缓存雪崩 缓存雪崩是指大量缓存数据同时…...
uniapp自定义拖拽排列
uniapp自定义拖拽排列并改变下标 <!-- 页面模板 --> <template><view class"container"><view v-for"(item, index) in list" :key"item.id" class"drag-item" :style"{transform: translate(${activeInde…...
汽车免拆诊断案例 | 2013款大众辉腾车发动机抖动
故障现象 一辆2013款大众辉腾车,搭载CMV发动机(燃油喷射方式为缸内直喷),累计行驶里程约为21.8万km。该车发动机怠速、加速时均有抖动,且组合仪表上的发动机故障灯异常点亮。 故障诊断 用故障检测仪检测࿰…...
【氮化镓】同质结GaN PiN二极管的重离子单粒子烧毁SEB
2025 年,范德堡大学的 A. S. Senarath 等人通过实验研究的方法,深入探究了在同质结 GaN 垂直 PIN 二极管中,边缘终止设计对重离子诱发的单粒子漏电(SELC)和单粒子烧毁(SEB)的影响。该研究获得了多个美国军方机构的支持,包括空军卓越辐射效应中心、海军研究办公室、能源…...
Java基础 4.23
1.包的命名 命名规则 只能包含数字 字母 下划线 小圆点 但不能用数字开头 不能是关键字或保留字 命名规范 一般是小写字母小圆点 一般是 com.公司名.项目名.业务模块名 比如 com.sina.crm.user 用户模块com.sina.crm.order 订单模块com.sina.crm.utils 工具类 2.常用的包…...
【学习准备】算法和开发知识大纲
1 缘起 今年(2025年)的职业升级结果:不通过。没办法升职加薪了。 需要开始完善学习,以应对不同的发展趋势,为了督促自己学习,梳理出相关学习大纲。 分为算法和开发两部分。 算法,包括基础算法和…...
Godot学习-3D基本环境设置以及3D角色移动
文章目录 一、新建项目和导入资产二、创建玩家场景1.修改模型节点类型为CharacterBody3D2.添加碰撞对象并且设置碰撞区域3.根据动画的运动状态调整碰撞区域 三、使用CSGMesh3D创建地面1.设置网格尺寸2.设置网格材质 四、添加3D相机和光照五、为角色移动编写代码1.基本移动和旋转…...
高效并发编程:无锁编程
无锁编程是一种并发编程的技术,旨在避免使用传统的锁机制来保护共享数据。相比有锁编程,无锁编程可以提供更高的并发性能和可伸缩性。在无锁编程中,线程或进程通过使用原子操作、CAS(Compare-and-Swap)等技术来实现对共…...
Java与C语言核心差异:从指针到内存管理的全面剖析
🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:AI 【前言】 在计算机编程领域,Java和C语言都是极具影响力的编程语言。Java以其跨平台性、安全性和面向对象…...
亚远景-基于ASPICE标准的汽车软件过程优化路径
基于ASPICE标准的汽车软件过程优化路径可以从以下几个方面展开: 1. 评估现状与设定目标 评估现状 :企业需要对当前的软件开发过程进行全面评估,识别与ASPICE标准之间的差距,明确薄弱环节。 设定目标 :根据评估结果和…...
集结号海螺捕鱼游戏源码解析(第三篇):拉霸机模块开发详解与服务器开奖机制
本篇聚焦“拉霸机”子游戏模块,全面剖析客户端滚轮动画机制、服务端中奖算法、中奖广播同步与配置解析方式,适用于技术团队针对拉霸玩法的二次开发与稳定性优化。 一、模块目录结构说明 拉霸机模块的源码目录一般如下: 子游戏/slot_machine…...
图聚类中的亲和力传播
图中展示的是Affinity Propagation(亲和力传播)算法中的一个关键步骤——更新吸引度矩阵。Affinity Propagation是一种聚类算法,它通过消息传递的方式找到数据集中的代表性样本(称为exemplar或原型),并将其…...
Apache中间件解析漏洞与安全加固
Apache作为全球使用最广泛的Web服务器,其灵活性和模块化设计使其成为开发者的首选。然而,其解析机制和配置不当可能导致严重的安全风险。本文将从漏洞原理、攻击案例和安全配置三个维度,结合真实场景,解析…...
MyBatis-Plus分页插件的使用
从MyBatis-Plus 3.4.0开始,不再使用旧版本的PaginationInterceptor ,而是使用MybatisPlusInterceptor。 下面是MyBatis-Plus 3.4.3.3新版分页的使用方法。 配置 使用分页插件需要配置MybatisPlusInterceptor,将分页拦截器添加进来ÿ…...
集结号海螺捕鱼游戏源码解析(第二篇):水浒传捕鱼模块逻辑与服务器帧同步详解
本篇将全面解构“水浒传”子游戏的服务端核心逻辑、帧同步机制、鱼群刷新规则、客户端命中表现与服务器计算之间的协同方式,聚焦于 C 与 Unity3D 跨端同步的真实实现过程。 一、水浒传捕鱼模块资源结构 该模块包含三部分核心目录: 子游戏/game_shuihuz…...
开发体育直播系统后台权限设计实践分享|ThinkPHP 技术栈落地案例
今天我们分享的是一套由 东莞梦幻网络科技 自研的体育直播源码,在 ThinkPHP MySQL 技术栈的加持下,后台权限系统如何从0到1落地,并支撑整个平台稳定运行。 一、整体架构设计 用户端(APP / H5 / PC)↓ 前端接口层&am…...
onlyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
文章目录 oonlyoffice历史版本功能实现 (编辑器功能实现)springbootvue2前提 需要注意把这个 (改成自己服务器的ip或者域名) 改成 自己服务器的域名或者地址1. onloyoffice 服务器部署 搜索其他文章2. 前段代码 vue 22.1 需要注意把这个 (改成自己服务器…...
【漫话机器学习系列】219.支持向量机分类器(Support Vector Classifier)
图解支持向量机分类器(Support Vector Classifier) 在机器学习的分类模型中,支持向量机(Support Vector Machine,SVM)是一种功能强大且广泛应用的监督学习算法。它尤其擅长解决小样本、高维度的数据问题&a…...
深入解析 Spring Boot Test:架构、核心组件与最佳实践
深入解析 Spring Boot Test:架构、核心组件与最佳实践 在现代软件开发中,测试是确保应用程序质量的关键环节。Spring Boot Test作为Spring Boot框架的一部分,提供了一套强大且灵活的测试工具,帮助开发者高效地测试Spring Boot应用…...
Sklearn 与 TensorFlow 机器学习实用指南-第八章 降维-笔记
补充: 本文是关于《Sklearn 与 TensorFlow 机器学习实用指南》的学习笔记,基于八、降维 - 【布客】Sklearn 与 TensorFlow 机器学习实用指南 第二版,感谢译者 本文和原文的区别: 本文会更精简、系统地表述书中概念,…...
动态贴纸+美颜SDK的融合实现:底层架构与性能优化技术全解析
如今,美颜动态贴纸功能已经成为提升用户粘性与平台竞争力的“标配”。但从技术实现角度看,如何高效融合动态贴纸与美颜SDK,并在保证画质与流畅度的前提下实现稳定输出,仍然是一项复杂且极具挑战的工程。 本文将深入解析“动态贴纸…...
Git简介与入门
Git的发明 Git由著名的Linux创始人linus于2005年发明(所以git的界面、使用方式与Linux挺像的,即命令行方式) 经过发展,现在广泛应用于代码管理与团队协作。 Git特性 Git是分布式版本控制系统 分布式 每个开发者拥有完整仓库&…...
车载信息安全架构 --- 汽车网络安全
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...
Elasticsearch 堆内存使用情况和 JVM 垃圾回收
作者:来自 Elastic Kofi Bartlett 探索 Elasticsearch 堆内存使用情况和 JVM 垃圾回收,包括最佳实践以及在堆内存使用过高或 JVM 性能不佳时的解决方法。 堆内存大小是分配给 Elasticsearch 节点中 Java 虚拟机的 RAM 数量。 从 7.11 版本开始ÿ…...
基于UDP协议的群聊服务器开发(C/C++)
目录 服务器 一、通信 打开网络文件 绑定IP地址与端口号 接收信息 二、数据处理 客户端 三、端口绑定 四、收发信息 五、源码 服务器 在服务器架构设计中,模块解耦是保障系统可维护性的核心准则。本方案采用分层架构将核心功能拆解为通信层与业务处理层两…...
通过自定义序列化来格式化BigDecimal带千分符的字符串
首先,你需要创建一个自定义的 JsonSerializer 来格式化 BigDecimal 为带千分符的字符串。 public class BigDecimalWithCommaSerializer extends JsonSerializer<BigDecimal> {Overridepublic void serialize(BigDecimal value, JsonGenerator gen, Serialize…...
VulnHub-DarkHole_2靶机渗透教程
1.靶机部署 [Onepanda] Mik1ysomething 靶机下载:https://download.vulnhub.com/darkhole/darkhole_2.zip 直接使用VMware导入打开就行 注意:靶机的网络连接模式必须和kali一样,让靶机跟kali处于同一网段,这样kali才能扫出靶机…...
cf | Common Multiple
题目: 代码: 无注释版: #include<bits/stdc.h> using namespace std; #define int long long signed main(){int t;cin>>t;while(t--){int n;cin>>n;map<int,int> mp;mp.clear();for(int i1;i<n;i){int x;cin…...
leetcode hot100尝试1
目录 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 你可以按任意顺序返回答案。 c m…...
大模型Agent
一 大模型Agent是什么 (一)大模型Agent是指基于大语言模型的,能使用工具与外部世界进行交互的计算机程序 感知(Perception): ● 家庭助理通过摄像头、麦克风、传感器等设备获取家庭成员的活动信息和环境状…...
阻塞队列的介绍和简单实现——多线程编程简单案例[多线程编程篇(4)]
目录 前言 阻塞队列 阻塞队列相比普通队列的优势 1.天然线程安全 2.实现生产者-消费者模型更加简单 3.自动等待与唤醒 生产者-消费者模型 JAVA标准库中的阻塞队列 阻塞队列的简单实现 前言 在现代软件开发中,多线程编程能力已经成为程序员必须掌握的一项核心…...
服务器配置环境-condapytorch_20250422
文章目录 前言一、conda环境1.1 创建固定python版本的conda环境1.2 激活 Conda 环境1.3 关闭 Conda 环境 二、版本查看CUDA版本当电脑里有多个CUDN时 对照表下载 资源 前言 一、conda环境 1.1 创建固定python版本的conda环境 conda create --name tang_py_3.12 python3.12.41…...