Redisson分布式锁(WatchDog分析,浅浅看下源码)

2024-03-19 00:36

本文主要是介绍Redisson分布式锁(WatchDog分析,浅浅看下源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

带大家简单了解下Redisson的看门狗机制,这个面试中也比较常见。

目录

  • WatchDog(看门狗)机制
  • 开启WatchDog(看门狗)
  • 浅看下源码

WatchDog(看门狗)机制

Redisson看门狗机制是用于解决在业务运行时间大于锁失效时间的情况,即自动续期,当某用户执行抢占锁执行需要40秒,而锁有效期为30秒,到期后锁就有可能被其他用户抢占,这个时候看门狗机制就可以帮其自动续期至执行结束。

开启WatchDog(看门狗)

引入maven

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.17.6</version>
</dependency>

先来看下redisson的简单使用(开门狗机制未开启时

@RequestMapping("/watch_dog")
public String watchDog(){// 简单配置RedissonClientConfig config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");RedissonClient redisson = Redisson.create(config);// 获取锁RLock lock = redisson.getLock("anyLock");try {// 尝试获取锁,最多等待3秒,锁定之后3秒自动解锁(锁释放程序照跑)boolean isLocked = lock.tryLock(3, 3, TimeUnit.SECONDS);if (isLocked) {System.out.println(Thread.currentThread().getName()+":还没睡觉");Thread.sleep(3000);System.out.println(Thread.currentThread().getName()+":睡眠了3秒钟");// 业务逻辑Thread.sleep(5000);System.out.println(Thread.currentThread().getName()+":睡眠了5秒钟");}} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁(查询当前线程是否保持锁定)if (lock.isHeldByCurrentThread()) {lock.unlock();}}// 关闭RedissonClientredisson.shutdown();return Thread.currentThread().getName();
}

通过以下结果可以发现,当http-nio-19428-exec-1线程还在执行时,3秒后锁过期导致http-nio-19428-exec-4就可以抢占了锁

在这里插入图片描述

开启看门狗机制,以下是各类情况:
//
// //拿锁失败会不停重试
// //具有 Watch Dog 自动延期机制,默认续30s 每隔30/3=10 秒续到30s
// lock.lock();
//
// //businessLock.tryTime() 秒之后停止重试加锁,返回false
// //具有 Watch Dog 自动延期机制,默认续30s 每隔30/3=10 秒续到30s
// boolean locked1 = lock.tryLock(businessLock.tryTime(), businessLock.timeUnit());
//
// //businessLock.tryTime() 秒之后停止重试加锁,返回false
// //不具有 Watch Dog 自动延期机制
// boolean locked2 = lock.tryLock(businessLock.tryTime(), businessLock.expire(), businessLock.timeUnit());
//
// //businessLock.tryTime() 秒之后停止重试加锁,返回false
// //只有 leaseTime(默认-1) 等于 -1 时(示具体版本情况而定),才具有 Watch Dog 自动延期机制,默认续30s 每隔30/3=10 秒续到30s
// boolean locked3 = lock.tryLock(businessLock.tryTime(), -1, businessLock.timeUnit());

lock()方法是阻塞获取锁的方式,如果当前锁被其他线程持有,则当前线程会一直阻塞等待获取锁,直到获取到锁或者发生超时或中断等情况才会结束等待。该方法获取到锁之后可以保证线程对共享资源的访问是互斥的,适用于需要确保共享资源只能被一个线程访问的场景。Redisson 的 lock() 方法支持可重入锁和公平锁等特性,可以更好地满足多线程并发访问的需求。
tryLock()方法是一种非阻塞获取锁的方式,在尝试获取锁时不会阻塞当前线程,而是立即返回获取锁的结果,如果获取成功则返回 true,否则返回false。Redisson 的 tryLock() 方法支持加锁时间限制、等待时间限制以及可重入等特性,可以更好地控制获取锁的过程和等待时间,避免程序出现长时间无法响应等问题。
按个人理解:lock()会一直自旋等待锁,而tryLock()尝试获取锁后快速返回结果

以最后一种情况为例,修改代码如下:

//尝试获取锁,最多等待6秒
boolean isLocked = lock.tryLock(6, -1, TimeUnit.SECONDS);

通过以下结果可以看出,在http-nio-19428-exec-2无法并没有自动释放锁
在这里插入图片描述

这时候大家就会问了,不是没设置过期时间么,当然不会自动失效啦,我也是带着这个疑问,饭约了资料以及一些博主的讲解,其实redisson的看门狗机制主要是用于以下情况的:
分布式锁在执行过程中若锁失效的情况则会导致锁被其他线程占用,但是若锁不设置失效时长,虽然有逻辑控制释放锁,若出现宕机时则会导致锁未释放而死锁,而redission的看门狗机制就可以解决这个死锁问题,宕机后在默认的配置下最长30s 的时间后,这个锁就自动释放了。

浅看下源码

//  源码这里解释前面三四点为何出现leaseTime问题,该版本为leaseTime>0即不触发
//  源码跟进 tryLock->tryAcquire->tryAcquireAsync

在这里插入图片描述

<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {return this.evalWriteAsync(this.getRawName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);", Collections.singletonList(this.getRawName()), new Object[]{unit.toMillis(leaseTime), this.getLockName(threadId)});
}

执行 Redis 的 Lua 脚本来加锁

if (redis.call(‘exists’, KEYS[1]) == 0)
then redis.call(‘hincrby’,KEYS[1], ARGV[2], 1);
redis.call(‘pexpire’, KEYS[1], ARGV[1]);
return nil;
end;
if (redis.call(‘hexists’, KEYS[1], ARGV[2]) == 1)
then redis.call(‘hincrby’, KEYS[1], ARGV[2], 1);
redis.call(‘pexpire’,KEYS[1], ARGV[1]);
return nil;
end;
return redis.call(‘pttl’,KEYS[1]);

具体的源码解析我觉得可以看看该博客 https://www.cnblogs.com/Leo_wl/p/16600565.html

这篇关于Redisson分布式锁(WatchDog分析,浅浅看下源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/824220

相关文章

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

python-nmap实现python利用nmap进行扫描分析

《python-nmap实现python利用nmap进行扫描分析》Nmap是一个非常用的网络/端口扫描工具,如果想将nmap集成进你的工具里,可以使用python-nmap这个python库,它提供了... 目录前言python-nmap的基本使用PortScanner扫描PortScannerAsync异

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S