尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Redisson 看门狗原理详解

Redisson 看门狗原理详解 1. 什么是看门狗机制在分布式锁的实现中一个核心挑战是当持有锁的客户端因为 GC 停顿、网络延迟或进程假死等原因未能及时释放锁时如何避免锁被永久占用导致其他客户端无限等待Redisson 的看门狗Watchdog机制正是为了解决这个问题而设计的。它是一种锁自动续期机制。当客户端成功获取一个 Redisson 锁默认指RLock时如果未指定锁的过期时间leaseTime看门狗便会启动一个后台守护线程定期检查客户端是否还持有锁并自动为锁续期从而防止锁因业务执行时间过长而意外过期释放。2. 看门狗的核心工作流程看门狗机制的工作流程可以概括为以下几个关键步骤加锁客户端调用lock()方法尝试加锁。锁设置与看门狗启动如果加锁时未指定leaseTime锁租约时间Redisson 会在 Redis 中创建一个 key其默认过期时间为30 秒。同时客户端会启动一个看门狗后台线程。如果指定了leaseTime则 Redis key 的过期时间就是该值并且不会启动看门狗线程。定期续期看门狗线程会以锁过期时间的 1/3为周期默认 30 秒 / 3 10 秒进行调度。在每次调度时它检查当前客户端是否仍持有该锁即检查本地的一个并发标记。执行续期如果检查通过看门狗线程会向 Redis 发送一个PEXPIRE命令将锁 key 的过期时间重新设置为 30 秒即“续命”。业务执行与释放客户端业务逻辑执行完毕后调用unlock()方法。该方法会删除 Redis 中的锁 key并中断看门狗线程的续期循环。异常处理如果客户端在持有锁期间崩溃看门狗线程也会随之停止锁 key 将在最后一次续期后的 30 秒自动过期从而避免死锁。3. 源码逻辑浅析看门狗的核心逻辑位于RedissonLock类的scheduleExpirationRenewal方法中。以下是一个简化的逻辑说明// 伪代码展示核心逻辑 private void scheduleExpirationRenewal(long threadId) { // 1. 创建一个定时任务 Timeout task commandExecutor.getConnectionManager().newTimeout(new TimerTask() { Override public void run(Timeout timeout) throws Exception { // 2. 检查当前线程是否还持有锁通过一个本地 ConcurrentMap if (internalLockLeaseTime ! null internalLockLeaseTime -1) { // 3. 如果仍持有则执行续期命令 (PEXPIRE) RFutureBoolean future commandExecutor.evalWriteAsync( getName(), 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(getName()), internalLockLeaseTime, getLockName(threadId)); // 4. 续期成功后递归调用自己安排下一次续期 future.onComplete((res, e) - { if (e null res) { scheduleExpirationRenewal(threadId); } }); } } }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS); // 延迟时间为租约时间的1/3 // 将定时任务保存起来以便在解锁时取消 expirationRenewalMap.put(getEntryName(), task); }关键点递归调用每次成功续期后会再次调用scheduleExpirationRenewal从而形成一个周期性的续期循环。取消机制在unlock()方法中会从expirationRenewalMap中取出并取消这个定时任务。4. 关键特性与注意事项4.1 默认时间参数锁默认租约时间lockWatchdogTimeout默认30 秒。可通过Config.setLockWatchdogTimeout()全局配置。续期周期默认是租约时间的 1/3即10 秒。4.2 看门狗的启用条件启用使用lock()、tryLock()等方法且未指定leaseTime参数时。也就是leaseTime -1时。不启用加锁时指定了leaseTime。使用lockInterruptibly()等方法且未指定租期但看门狗仍会工作原理相同。4.3 优点避免锁意外释放业务执行时间超过预期时锁不会自动过期提高了安全性。简化使用开发者无需精确估算业务耗时也无需手动续期。4.4 潜在风险与规避业务逻辑阻塞导致锁长期占用如果业务代码发生死循环或长时间阻塞看门狗会持续续期导致锁一直被占用。需确保业务逻辑有超时控制。时钟漂移问题客户端与 Redis 服务器时钟不一致可能影响续期准确性。确保使用 NTP 同步时间。Redisson 客户端宕机客户端进程崩溃看门狗线程停止锁最终会过期这是符合预期的安全机制。5. 最佳实践建议评估业务耗时对于执行时间相对稳定且可预估的短任务可以考虑指定合理的leaseTime避免启用看门狗减少资源开销。监控与告警监控 Redisson 锁的持有时间如果发现锁被持续续期且长时间未释放可能意味着业务逻辑阻塞需要告警。避免在锁内进行耗时不确定的操作如远程 HTTP 调用、复杂文件 IO 等这些操作可能导致锁持有时间过长。理解“默认启用”明确 Redissonlock()默认会启动看门狗在架构设计时需考虑其资源消耗和续期行为。6. 注意事项1.看门狗不会因为线程异常但是没有释放锁而停止反而会不断的重置30秒只有线程奔溃后看门狗才会自动释放锁所以建议把unlock()放到finally里面这样能够防止线程在发生异常时造成死锁。2.看门狗的30秒后锁的过期只是对应的key的逻辑过期而已并没有物理删除。如果有人来访问它Redis 会先把它删掉再返回空如果没人访问它会在后台慢慢被清理掉。总结来说Redisson 的看门狗机制通过后台守护线程定期续期巧妙地解决了分布式锁在客户端存活但业务未完成场景下的过期问题是 Redisson 实现可重入、高可靠分布式锁的核心组件之一。正确理解其原理和适用场景有助于在项目中更安全、高效地使用分布式锁。
返回列表