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

相关文章

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

基于Redisson实现分布式系统下的接口限流

《基于Redisson实现分布式系统下的接口限流》在高并发场景下,接口限流是保障系统稳定性的重要手段,本文将介绍利用Redisson结合Redis实现分布式环境下的接口限流,具有一定的参考价值,感兴趣... 目录分布式限流的核心挑战基于 Redisson 的分布式限流设计思路实现步骤引入依赖定义限流注解实现

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499