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

news2024/9/20 16:08:20

带大家简单了解下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(){
    // 简单配置RedissonClient
    Config 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();
        }
    }

    // 关闭RedissonClient
    redisson.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1537200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WSL2的安装步骤

WSL2&#xff08;Windows Subsystem for Linux 2&#xff09;是微软公司开发的一项创新性技术&#xff0c;它在Windows操作系统上提供了一个完整的Linux内核&#xff0c;并允许用户在Windows环境中运行Linux发行版。之前想在Windows上使用Linux系统必须先安装VirtualBox或VMWar…

PTA 抢红包 25分 (JAVA)

题目描述 没有人没抢过红包吧…… 这里给出N个人之间互相发红包、抢红包的记录&#xff0c;请你统计一下他们抢红包的收获。 输入格式&#xff1a; 输出格式&#xff1a; 按照收入金额从高到低的递减顺序输出每个人的编号和收入金额&#xff08;以元为单位&#xff0c;输出小…

JsonUtility.ToJson 和UnityWebRequest 踩过的坑记录

项目场景&#xff1a; 需求&#xff1a;我在做网络接口链接&#xff0c;使用的unity自带的 UnityWebRequest &#xff0c;数据传输使用的json&#xff0c;json和自定义数据转化使用的也是unity自带的JsonUtility。使用过程中发现两个bug。 1.安全验证失败。 报错为&#xff1a…

day-24 跳跃游戏 III

思路&#xff1a;dfs方法&#xff0c;从开始节点开始进行深度优先遍历&#xff0c;利用一个数组vis[]记录该位置是否被访问过&#xff0c;如果遍历到一个已经访问的位置&#xff0c;返回false 如果遍历到某位置的值为0&#xff0c;返回true code: class Solution {public boo…

006_【基础篇】springboot整合Mybatis

SpringBoot 整合 Mybatis 只需要两步&#xff1a; 案例&#xff1a; 创建数据库 在 IDEA 提供的插件的内置的数据库图形化界面(其他图形化界面软件也可以&#xff0c;都一样&#xff09; 中创建以下数据库&#xff1a; create database if not exists mybatis;use mybatis…

类于对象(上)--- 类的定义、访问限定符、计算类和对象的大小、this指针

在本篇中将会介绍一个很重要和很基础的Cpp知识——类和对象。对于类和对象的篇目将会有三篇&#xff0c;本篇是基础篇&#xff0c;将会介绍类的定义、类的访问限定符符和封装、计算类和对象的大小、以及类的 this 指针。目录如下&#xff1a; 目录 1. 关于类 1.1 类的定义 2 类…

Spring Boot项目中使用MyBatis连接达梦数据库6

在开发中&#xff0c;使用Spring Boot框架结合MyBatis来操作数据库是一种常见的做法。本篇博客将介绍如何在Spring Boot项目中配置MyBatis来连接达梦数据库6&#xff0c;并提供一个简单的示例供参考。(达梦六不仅分表还分模式.) 我拿SYSTEM表的LPS模式下面Student表做案例。 1.…

AI系统性学习—LangChain入门

文章目录 1、LangChain入门1.1 简介1.2 架构1.3 核心概念1.2 快速入门1.3 安装 2、LangChain Prompt Template2.1 什么是提示词模版2.1 创建一个提示词模版2.2 聊天消息提示词模版2.3 模版追加示例 3、语言模型3.1 LLM基础模型3.2 LangChain聊天模型3.3 自定义模型3.4 输出解析…

Word文档密码设置:Python设置、更改及移除Word文档密码

给Word文档设置打开密码是常见的Word文档加密方式。为Word文档设置打开密码后&#xff0c;在打开该文档时&#xff0c;需要输入密码才能预览及编辑&#xff0c;为Word文档中的信息提供了有力的安全保障。如果我们需要对大量的Word文档进行加密、解密处理&#xff0c;Python是一…

JavaScript parseInt() 函数

JavaScript parseInt() 函数 从官方理解&#xff1a; parseInt() 函数解析字符串并返回整数。 radix 参数用于指定使用哪种数字系统&#xff0c;例如基数为 16&#xff08;十六进制&#xff09;表示字符串中的数字应从十六进制数解析为十进制数。 如果 radix 参数被省略&…

基于迭代正则化的边缘投影轮廓测量修复

文章名称&#xff1a;Inpainting For Fringe Projection Profilometry Based on Iterative Regularization 代码地址&#xff1a; &#x1f4a1; 摘要&#xff1a;本文提出了一种基于迭代正则化技术的新的条纹投影轮廓术&#xff08;Fringe Projection Profilometry, FPP&…

CrossOver 23 用户可以免费升级到 CrossOver24吗?CrossOver用户如何升级呢?

也就是上个月&#xff08;2024年2月底&#xff09;左右&#xff0c;CrossOver 刚刚更新了 24 版本&#xff0c;CrossOver更新的内容有哪些&#xff0c;大家可以参考这篇文章&#xff1a;CrossOver24.0新功能介绍&#xff0c;这篇文章详细介绍了CrossOver24有哪些新特点&#xf…

Harbor高可用(nginx和keepalived)

Harbor高可用&#xff08;nginx和keepalived&#xff09; 文章目录 Harbor高可用&#xff08;nginx和keepalived&#xff09;1.Harbor高可用集群部署架构1.1 主机初始化1.1.1 设置网卡名和ip地址1.1.2 设置主机名1.1.3 配置镜像源1.1.4 关闭防火墙1.1.5 禁用SELinux1.1.6 设置时…

软考90-上午题-【操作系统】-死锁

一、同类资源分配不当引起死锁 系统中有m个资源&#xff0c;被n个进程共享&#xff0c;每个进程都要求k个资源。 当m < n*k时&#xff0c;即&#xff1a;资源数<进程所要求的总数时&#xff0c;可能会引起死锁。&#xff08;但是不一定&#xff01;&#xff09; 例如&…

初识数据库|数据库的特点、分类以及作用

数据库系统&#xff08;DateBase System&#xff0c;简称DBS&#xff09;是指在计算机系统中引入数据库后的系统构成&#xff0c;由计算机硬件&#xff0c;操作系统&#xff0c;DBMS&#xff0c;DB&#xff0c;应用程序和用户以及数据库开发和管理人员等组成。 &#xff08;一…

RK3568 安装Miniconda3

下载链接:https://download.csdn.net/download/smile_5me/89012477?spm=1001.2014.3001.5503 需要RK3568运行Ubuntu,之前的文章有关于如何安装Ubuntu以及遇到的问题 1、 拷贝 Miniconda3-latest-Linux-aarch64.sh 到开发板 2、运行安装 Miniconda3-latest-Linux-aarch64.…

Maven 环境一键部署

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…

Oracle 写丢失保护/影子表空间(Lost Write Protection with Shadow Tablespace)

写丢失是Oracle数据库与独立I/O子系统交互时一种错误场景。假如Oracle发出的写磁盘命令&#xff0c;I/O子系统也返回成功写磁盘的消息&#xff08;但数据此时可能依然在I/O系统缓存中&#xff09;&#xff0c;如果在I/O系统实际写盘之前Oracle再次读取该数据&#xff0c;则I/O系…

sparksql简介

什么是sparksql sparksql是一个用来处理结构话数据的spark模块&#xff0c;它允许开发者便捷地使用sql语句的方式来处理数据&#xff1b;它是用来处理大规模结构化数据的分布式计算引擎&#xff0c;其他分布式计算引擎比较火的还有hive&#xff0c;map-reduce方式。 sparksql…

网络编程 - 套接字

1、预备知识 1.1、理解源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址&#xff1b; 思考: 我们光有IP地址就可以完成通信了嘛? 想象一下发qq消息的例子, 有了IP地址能够把消息发送到对方的机器上, 但是还需要有一个其他的标识来区分…