一篇文章看懂Redission原理

文章目录

  • ☃️可重入锁原理
  • ☃️锁重试和WatchDog机制
  • ☃️MutiLock原理


在这里插入图片描述

在这里插入图片描述


上一篇文章讲解了 Rediision的使用 ,这篇文章讲解其原理

☃️可重入锁原理

Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state=0,假如有人持有这把锁,那么state=1,如果持有这把锁的人再次持有这把锁,那么state就会+1 ,如果是对于synchronized而言,他在c语言代码中会有一个count,原理和state类似,也是重入一次就加一,释放一次就-1 ,直到减少成0 时,表示当前这把锁没有被人持有。

Redission 中,我们的也支持支持可重入锁

在分布式锁中,他采用hash结构用来存储锁,其中大key表示表示这把锁是否存在,用小key表示当前这把锁被哪个线程持有,所以接下来我们一起分析一下当前的这个lua表达式

这个地方一共有3个参数

KEYS[1] : 锁名称

ARGV[1]: 锁失效时间

ARGV[2]: id + “:” + threadId; 锁的小key

exists: 判断数据是否存在 name:是lock是否存在,如果==0,就表示当前这把锁不存在

redis.call('hset', KEYS[1], ARGV[2], 1);此时他就开始往redis里边去写数据 ,写成一个hash结构

Lock{
id + **":"** + threadId : 1
}

如果当前这把锁存在,则第一个条件不满足,再判断

redis.call('hexists', KEYS[1], ARGV[2]) == 1

此时需要通过大key+小key判断当前这把锁是否是属于自己的,如果是自己的,则进行

redis.call('hincrby', KEYS[1], ARGV[2], 1)

将当前这个锁的value进行+1 ,redis.call('pexpire', KEYS[1], ARGV[1]); 然后再对其设置过期时间,如果以上两个条件都不满足,则表示当前这把锁抢锁失败,最后返回pttl,即为当前这把锁的失效时间

如果小伙帮们看了前边的源码, 你会发现他会去判断当前这个方法的返回值是否为null,如果是null,则对应则前两个if对应的条件,退出抢锁逻辑,如果返回的不是null,即走了第三个分支,在源码处会进行while(true)的自旋抢锁。

"if (redis.call('exists', KEYS[1]) == 0) then " +"redis.call('hset', 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]);"

在这里插入图片描述


☃️锁重试和WatchDog机制

说明tryLock的源码解析以及其看门狗原理,所以笔者在这里给大家分析lock()方法的源码解析,希望大家在学习过程中,能够掌握更多的知识

抢锁过程中,获得当前线程,通过tryAcquire进行抢锁,该抢锁逻辑和之前逻辑相同

1、先判断当前这把锁是否存在,如果不存在,插入一把锁,返回null

2、判断当前这把锁是否是属于当前线程,如果是,则返回null

所以如果返回是null,则代表着当前这哥们已经抢锁完毕,或者可重入完毕,但是如果以上两个条件都不满足,则进入到第三个条件,返回的是锁的失效时间,同学们可以自行往下翻一点点,你能发现有个while( true) 再次进行tryAcquire进行抢锁

long threadId = Thread.currentThread().getId();
Long ttl = tryAcquire(-1, leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {return;
}

接下来会有一个条件分支,因为lock方法有重载方法,一个是带参数,一个是不带参数,如果带带参数传入的值是-1,如果传入参数,则leaseTime是他本身,所以如果传入了参数,此时leaseTime != -1 则会进去抢锁,抢锁的逻辑就是之前说的那三个逻辑

if (leaseTime != -1) {return tryLockInnerAsync(waitTime, leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}

如果是没有传入时间,则此时也会进行抢锁, 而且抢锁时间是默认看门狗时间 commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout()

ttlRemainingFuture.onComplete((ttlRemaining, e) 这句话相当于对以上抢锁进行了监听,也就是说当上边抢锁完毕后,此方法会被调用,具体调用的逻辑就是去后台开启一个线程,进行续约逻辑,也就是看门狗线程

RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(waitTime,commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(),TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.onComplete((ttlRemaining, e) -> {if (e != null) {return;}// lock acquiredif (ttlRemaining == null) {scheduleExpirationRenewal(threadId);}
});
return ttlRemainingFuture;

此逻辑就是续约逻辑,注意看commandExecutor.getConnectionManager().newTimeout() 此方法

Method( new TimerTask() {},参数2 ,参数3 )

指的是:通过参数2,参数3 去描述什么时候去做参数1的事情,现在的情况是:10s之后去做参数一的事情

因为锁的失效时间是30s,当10s之后,此时这个timeTask 就触发了,他就去进行续约,把当前这把锁续约成30s,如果操作成功,那么此时就会递归调用自己,再重新设置一个timeTask(),于是再过10s后又再设置一个timerTask,完成不停的续约

那么大家可以想一想,假设我们的线程出现了宕机他还会续约吗?当然不会,因为没有人再去调用renewExpiration这个方法,所以等到时间之后自然就释放了。

private void renewExpiration() {ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());if (ee == null) {return;}Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {@Overridepublic void run(Timeout timeout) throws Exception {ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());if (ent == null) {return;}Long threadId = ent.getFirstThreadId();if (threadId == null) {return;}RFuture<Boolean> future = renewExpirationAsync(threadId);future.onComplete((res, e) -> {if (e != null) {log.error("Can't update lock " + getName() + " expiration", e);return;}if (res) {// reschedule itselfrenewExpiration();}});}}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);ee.setTimeout(task);
}

☃️MutiLock原理

为了提高redis的可用性,我们会搭建集群或者主从,现在以主从为例

此时我们去写命令,写在主机上, 主机会将数据同步给从机,但是假设在主机还没有来得及把数据写入到从机去的时候,此时主机宕机,哨兵会发现主机宕机,并且选举一个slave变成master,而此时新的master中实际上并没有锁信息,此时锁信息就已经丢掉了。

在这里插入图片描述

为了解决这个问题,redission提出来了MutiLock锁,使用这把锁咱们就不使用主从了,每个节点的地位都是一样的, 这把锁加锁的逻辑需要写入到每一个主丛节点上,只有所有的服务器都写入成功,此时才是加锁成功,假设现在某个节点挂了,那么他去获得锁的时候,只要有一个节点拿不到,都不能算是加锁成功,就保证了加锁的可靠性。

在这里插入图片描述

那么 MutiLock 加锁原理是什么呢?笔者画了一幅图来说明

当我们去设置了多个锁时,redission会将多个锁添加到一个集合中,然后用while循环去不停去尝试拿锁,但是会有一个总共的加锁时间,这个时间是用需要加锁的个数 * 1500ms ,假设有3个锁,那么时间就是4500ms,假设在这4500ms内,所有的锁都加锁成功, 那么此时才算是加锁成功,如果在4500ms有线程加锁失败,则会再次去进行重试.


在这里插入图片描述



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

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

相关文章

探索 cartesian_product:更深入理解范围库

理解范围库中的cartesian_product适配器 一、简介二、cartesian_product 适配器的动机三、将行为封装到算法中四、算法的局限性五、总结 一、简介 view::cartesian_product 适配器是range-v3 库一个新的组件。本文主要理解这个组件的功能以及它背后的设计理念&#xff0c;可以…

罗森伯格1800M 2000M 2400M 900M无源互调分析仪

在无线通信领域&#xff0c;频段是宝贵的资源&#xff0c;不同的通信系统通常会采用不同的频段以满足其传输需求。随着技术的发展&#xff0c;越来越多的通信系统被部署在各种频段上。为了准确、高效地测试和调试这些 信系统&#xff0c;各种测试设备也应运而生。源互调分析仪便…

Llama-3安装方法及应用

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Stable Diffusion直接生成IP三视图,一天设计100个?

AI都能直接生成IP形象三视图了&#xff01; SD生成一个动物Q版IP三视图模型。标准的三视图&#xff0c;并且极富设计感&#xff0c;IP设计师的好帮手&#xff0c;用来辅助创意&#xff0c;建模参考。这个模型主要是动物类&#xff0c;一般不需堆叠复杂的质量词&#xff0c;直接…

资源付费系统小程序APP公众号h5源码

&#x1f510; 揭秘“资源付费系统”&#xff1a;知识、技能与价值的交汇点 &#x1f48e; &#x1f31f; 引言&#xff1a;为何资源需要付费&#xff1f; 在数字化时代&#xff0c;我们周围充斥着大量的信息。但并非所有信息都具有同等的价值。其中&#xff0c;那些经过精心…

入门 Axure RP 9 | 原型设计基础教程

选择正确的原型设计工具并非易事&#xff0c;Axure RP 9能够快速完成原型设计。原型设计是一种经过时间考验的方法&#xff0c;可以将你的设计快速放置在用户的设备并交到他们手中。替代Axure RP 9的原型设计工具即时设计是一个完全集成的协同设计工具&#xff0c;无需使用不同…

Vue3中使用深度选择器不起作用

问题&#xff1a; 想要给这个菜单设置高度100%&#xff0c;使用深度样式选择器无效 这样写无效 但是如下在控制台写是有效果的 解决&#xff1a; 参考 解决方法是给这个组件增加一个根元素&#xff0c;然后再使用深度选择器

【C语言】指针的指针使用场景

前言 C 语言中&#xff0c;比较难理解的就是指针&#xff0c;完全搞懂了指针&#xff0c;那么C语言算是入了门。 指针中比较难理解的概念&#xff1a; 指针的指针。 指针的指针&#xff0c;刚开始看到这个概念&#xff0c;感觉头疼。但是我们在程序里面应用一次就能搞懂。 本文…

如何合并pdf文件到一个pdf

在现代办公和学习中&#xff0c;PDF格式的文件因其跨平台兼容性和安全性得到了广泛应用。然而&#xff0c;有时我们需要将多个PDF文件合并成一个&#xff0c;以便于管理和分享。本文将详细介绍几种合并PDF的方法&#xff0c;帮助读者轻松完成PDF文件的合并工作。 首先通过浏览器…

运营商二要素核验-手机号机主姓名核验接口-运营商二要素核验接口

通过电信运营商验证手机号码与姓名是否一致。广泛用于实名注册、风控审核等场景&#xff0c;如电商、游戏、直播、金融等需要用户实名认证的场景。支持携号转网核验。 更新周期&#xff1a;联通T1 电信T3 移动T3~5 均为工作日 接口地址&#xff1a; https://www.wapi.cn/api_de…

24V转5V降压芯片AH8642A:高效稳定的电源转换解决方案

### 24V转5V降压芯片AH8642A&#xff1a;高效稳定的电源转换解决方案 在电子设备日益增多的今天&#xff0c;电源转换效率和稳定性成为了设计中的关键因素。AH8642A是一款专为24V转5V设计的降压芯片&#xff0c;它以其高效率、宽输入电压范围和稳定的输出电压在电源转换领域脱颖…

JAVA:通过电信ctg.ag.sdk从电信物联平台AIOT获取设备上报数据的简单示例

一、问题场景 物联设备比如NB设备通过NB协议将数据传到电信平台后&#xff0c;我们的应用服务如何从电信平台获取可用的上报数据。以下通过电信开发者平台提供的SDK来简单演示下整个过程。 二、使用电信 SDK进行开发 电信AIOT物联平台提供了两种方式获取平台数据&#xff0c…

C语言 指针——字符数组与字符指针:字符串的表示与存储

目录 字符串常量 字符串变量&#xff1f; 字符数组的定义和初始化 字符指针的定义和初始化 将字符指针指向一个字符串 用字符数组保存一个字符串 将字符指针指向一个字符数组 使用字符指针的基本原则 使用指针的基本原则 字符串常量 字符串变量&#xff1f;  C 语言…

40. 【Java教程】数据库编程

本小节我们将学习如何使用 Java 语言结合数据库进行编程。注意&#xff0c;学习本小节需要你有一定的 SQL 基础&#xff0c;了解 MySQL 数据库的 基础 CRUD 操作。 本小节我们将选择开源免费的 MySQL 5.7 作为数据库&#xff0c;可以去官网下载并安装 MySQL。 通过本小节的学…

AI预测福彩3D采取888=3策略+和值012路或胆码测试6月13日新模型预测第3弹

今天咱们继续验证新模型的8码定位3&#xff0c;目前新模型新算法已连续命中2次。咱们重点是预测8码定位3&#xff0b;和值012胆码。有些朋友看到我最近两篇文章没有给大家提供缩水后的预测详情&#xff0c;在这里解释下&#xff1a;其实我每篇文章中既有8码定位&#xff0c;也有…

数据库学霸笔记

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

【MySQL】性能分析

https://www.bilibili.com/video/BV1Kr4y1i7ru/?p78 查看执行频次 查看当前数据库的 INSERT, UPDATE, DELETE, SELECT 访问频次&#xff1a; SHOW GLOBAL STATUS LIKE Com_______; 或者 SHOW SESSION STATUS LIKE Com_______; 慢查询日志 慢查询日志记录了所有执行时间超过指…

【JVM】之常见面试题

文章目录 1.JVM中的内存区域划分2.JVM的类加载机制2.1 加载2.2 验证2.3 准备2.4 解析2.5 初始化2.6 类加载的时机 3 类加载器4.双亲委派模型5.JVM中的垃圾回收策略5.1 找谁是垃圾5.1.1 引用计数法5.1.2 可达性分析法 5.2 释放垃圾5.2.1 标记清除算法5.2.2 复制算法5.2.3 标记整…

CorelDRAW2024永久破解版下载安装全教程!

在设计领域&#xff0c;精准和专业是至关重要的要素。随着技术的飞速发展&#xff0c;设计师们对软件的选择也越发严苛。CorelDRAW 2024中文版及其2024终身永久版、破解版&#xff0c;因其强大的功能和便捷的使用体验&#xff0c;成为了设计师们的首选之一。本文将深入探讨这一…

网络编程入门

文章目录 网络编程入门计算机网络基础计算机网络发展史TCP/IP模型网络应用模式 基于HTTP协议的网络资源访问HTTP&#xff08;超文本传输协议&#xff09;JSON格式requests库 基于传输层协议的套接字编程TCP套接字UDP套接字 网络应用开发发送电子邮件发送短信 网络编程入门 计算…