【分布式锁】Redisson分布式锁底层原理

news2024/11/27 10:36:24

文章目录

  • 前言
  • 原理分析
  • Redisson实现Redis分布式锁的底层原理
    • 1.加锁机制
    • 2.锁互斥机制
    • 3. watch dog自动延期机制
    • 4.可重入加锁机制
    • 5.释放锁机制
    • 6.上述Redis分布式锁的缺点

在这里插入图片描述

前言

现在最流行的redis分布式锁就是Redisson了,来看看它的底层原理就了解redis是如何使用分布式锁的了

原理分析

分布式锁要解决的是分布式环境下,并行相同代码的加锁功能;了解过redis分布式锁的人肯定知道,一开始redis作为分布式锁用的是setnx,再这基础上设置个定时过期时间,但这种方式有什么问题呢?

实际上看懂上图的人也就明白了那有什么问题,首先是原子性问题,setnx+过期时间这两个操作必须是原子性的,所以这可以用lua脚本解决

再然后是释放锁的时机该如何定?

  • 不管我们定多少过期时间,都不能保证,在这段时间内锁住的代码执行完成了,所以这个时间定多少都不好;

  • 如果不定时间,当执行完成后释放锁,问题就是如果执行到一半机器宕机,那这把锁就永远放不掉了
    那Redisson是如何解决上述问题的呢?

  • 它对代码进行了精简的封装,我们的使用非常简单,甚至我们不用主动设置过期时间

  • 它设计了个watch dog看门狗,每隔10秒会检查一下是否还持有锁,若持有锁,就给他更新过期时间30秒;通过这样的设计,可以让他在没有释放锁之前一直持有锁,哪怕宕机了,也能自动释放锁

  • 而不能获得锁的客户端则是不断循环尝试加锁

  • 通过记录锁的客户端id,可以把它设计成可重入锁

在这里插入图片描述

Redisson实现Redis分布式锁的底层原理

结合redisson原理图我们可以把加锁过程中的问题分成6块:

1.加锁机制

咱们来看上面那张图,现在某个客户端要加锁。如果该客户端面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。这里注意,仅仅只是选择一台机器!这点很关键!紧接着,就会发送一段lua脚本到redis上,那段lua脚本如下所示:
在这里插入图片描述

为啥要用lua脚本呢?因为一大坨复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性。

那么,这段lua脚本是什么意思呢?这里KEYS[1]代表的是你加锁的那个key,比如说:RLock lock = redisson.getLock(“myLock”);这里你自己设置了加锁的那个锁key就是“myLock”。

ARGV[1]代表的就是锁key的默认生存时间,默认30秒。ARGV[2]代表的是加锁的客户端的ID,类似于下面这样:8743c9c0-0795-4907-87fd-6c719a6b4586:1

给大家解释一下,第一段if判断语句,就是用“exists myLock”命令判断一下,如果你要加锁的那个锁key不存在的话,你就进行加锁。如何加锁呢?很简单,用下面的命令:hset myLock

8743c9c0-0795-4907-87fd-6c719a6b4586:1 1,通过这个命令设置一个hash数据结构,这行命令执行后,会出现一个类似下面的数据结构:

在这里插入图片描述

上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这个锁key完成了加锁。接着会执行“pexpire myLock 30000”命令,设置myLock这个锁key的生存时间是30秒。好了,到此为止,ok,加锁完成了。

2.锁互斥机制

那么在这个时候,如果客户端2来尝试加锁,执行了同样的一段lua脚本,会咋样呢?很简单,第一个if判断会执行“exists myLock”,发现myLock这个锁key已经存在了。接着第二个if判断,判断一下,myLock锁key的hash数据结构中,是否包含客户端2的ID,但是明显不是的,因为那里包含的是客户端1的ID。

所以,客户端2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。此时客户端2会进入一个while循环,不停的尝试加锁。

3. watch dog自动延期机制

客户端1加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?

简单!只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。

4.可重入加锁机制

那如果客户端1都已经持有了这把锁了,结果可重入的加锁会怎么样呢?比如下面这种代码:
在这里插入图片描述

这时我们来分析一下上面那段lua脚本。第一个if判断肯定不成立,“exists myLock”会显示锁key已经存在了。第二个if判断会成立,因为myLock的hash数据结构中包含的那个ID,就是客户端1的那个ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”

此时就会执行可重入加锁的逻辑,他会用:

incrby myLock 8743c9c0-0795-4907-87fd-6c71a6b4586:1 1 ,通过这个命令,对客户端1的加锁次数,累加1。此时myLock数据结构变为下面这样:
在这里插入图片描述

大家看到了吧,那个myLock的hash数据结构中的那个客户端ID,就对应着加锁的次数

5.释放锁机制

如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:“del myLock”命令,从redis里删除这个key。然后呢,另外的客户端2就可以尝试完成加锁了。这就是所谓的分布式锁的开源Redisson框架的实现机制。

一般我们在生产系统中,可以用Redisson框架提供的这个类库来基于redis进行分布式锁的加锁与释放锁。

6.上述Redis分布式锁的缺点

其实上面那种方案最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。此时就会导致多个客户端对一个分布式锁完成了加锁。这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。

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

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

相关文章

真香,聊聊 RocketMQ 5.0 的 POP 消费模式!

大家好,我是君哥。 大家都知道,RocketMQ 消费模式有 PULL 模式和 PUSH 模式,不过本质上都是 PULL 模式,而在实际使用时,一般使用 PUSH 模式。 不过,RocketMQ 的 PUSH 模式有明显的不足,主要体…

Unity 过场工具(Cutscene)设计(四) ——组件化设计

Unity 过场工具(Cutscene)设计(四) ——组件化设计 写到这一篇文章前就开始在考虑如何才能说清楚自己的设计思路,因为后续涉及到编辑器和Runtime框架的实际设计和实现过程,两者之间是互相有设计因果关系的。为了阐述自己的核心设计…

从0.5开始开发一个导购网站

提醒:文中没有具体如何修改的代码,只是提供了修改的思路。 为什么是从0.5开始呢? 因为这里借助了一个大佬的开源项目Springboot项目仿天猫商城: Springboot项目仿天猫商城 前台jsp页面 大佬的代码简洁,没有什么多余的功能&…

系统调用与API

系统调用介绍 什么是系统调用 为了让应用程序有能力访问系统资源,也为了让程序借助操作系统做一些由操作系统支持的行为,每个操作系统都会提供一套接口,以供应用程序使用。系统调用涵盖的功能很广,有程序运行所必需的支持&#xf…

leetCode刷题记录2

文章目录 hot100题560. 和为 K 的子数组581. 最短无序连续子数组 ▲617. 合并二叉树 hot100题 560. 和为 K 的子数组 560. 和为 K 的子数组 先暴力&#xff0c;过了再说 public int subarraySum(int[] nums, int k) {int ans 0;for (int i 0; i < nums.length; i) {in…

保姆级教程Windows11下安装RocketMQ

一、RocketMQ介绍 RocketMQ 是阿里巴巴开源的分布式消息中间件。支持事务消息、顺序消息、批量消息、定时消息、消息回溯等。它里面有几个区别于标准消息中件间的概念&#xff0c;如Group、Topic、Queue等。系统组成则由Producer、Consumer、Broker、NameServer等。 二、Rock…

vector类详解【c++】

&#x1f600;博主主页 &#x1f600;博主码云 目录 &#x1f3c5;vector简介&#x1f3c5;vector使用&#x1f3c6;vector的定义&#x1f3c6;vector iterator 的使用&#x1f3c6;vector 空间函数&#x1f3c6;vector的扩容问题&#x1f3c6;vector 增删查改&#x1f3c6;vec…

Python tkintertools 模块介绍(新版)

&#x1f680;tkintertools&#x1f680; The tkintertools module is an auxiliary module of the tkinter module tkintertools 模块是 tkinter 模块的辅助模块 Installation/模块安装 Stable version/稳定版本 Version/版本 : 2.6.1Release Date/发布日期 : 2023/05/21 p…

Edge 浏览器:隐藏功能揭秘与高效插件推荐

文章目录 一、前言二、Edge 的各种奇淫巧计2.1 开启 Edge 分屏功能2.2 启动 Edge 浏览器后直接恢复上次关闭前的页面2.3 解决 Edge 浏览器无法同步账号内容2.4 开启垂直标签页&#xff08;推荐&#xff09;2.5 设置标签分组&#xff08;推荐&#xff09;2.6 设置标签睡眠时间&a…

网络管理 - 简单网络管理协议 SNMP

文章目录 1 概述1.1 结构1.2 操作 2 SNMP2.1 报文格式2.2 五大报文类型2.3 三大组件 3 扩展3.1 网工软考真题 1 概述 #mermaid-svg-xmaaQjpp1bT1axfw {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xmaaQjpp1bT1axf…

实验篇(7.2) 01. 实验环境介绍 远程访问 ❀ Fortinet网络安全专家 NSE4

【简介】学习NSE4&#xff0c;如果只看文章而不动手做实验&#xff0c;就象耍流氓。为了有效的巩固学习到的内容&#xff0c;建议经常动手做实验。实验不怕出错&#xff0c;身经百战后&#xff0c;再在生产环境部署和配置FortiGate防火墙&#xff0c;就会做到胸有成竹。 虚拟实…

【网络协议详解】——RIP协议(学习笔记)

目录 &#x1f552; 1. IP路由协议概述&#x1f558; 1.1 路由表&#x1f558; 1.2 路由的度量尺度/度量值&#x1f558; 1.3 路由管理距离 &#x1f552; 2. RIP协议&#x1f558; 2.1 概述&#x1f558; 2.2 工作原理 &#x1f552; 3. 报文格式&#x1f558; 3.1 RIP 协议报…

【自动化测试】第一次项目实施

测试项目简介&#xff1a;基于python语言 跨平台的测试自动化工具&#xff0c;适用于后台、原生或混合型客户端应用的测试。它支持 Android、iOS、Web、后台、云服务和 Windows 端的 UI 自动化测试。 上手快&#xff0c;操作简单&#xff0c;只要有一点python基础&#xff0c…

5. 多线程并发锁

本文介绍了多线程并发下为了避免临界资源被抢占而出现的错误&#xff0c;引入了锁和原子操作 来解决。 一、问题分析 创建10个线程&#xff0c;每个线程实现往总进程加1万个数。则总进程会达到10万 #include<stdio.h> #include <unistd.h> #include<pthread.h…

路径规划算法:基于头脑风暴算法的路径规划算法- 附代码

路径规划算法&#xff1a;基于头脑风暴的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于头脑风暴的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法头脑…

强化学习-初步认识

前言 强化学习这个概念是2017年Alpha Go战胜了当时世界排名第一的柯洁而被大众知道&#xff0c;后面随着强化学习在各大游戏比如王者荣耀中被应用&#xff0c;而被越来越多人熟知。王者荣耀AI团队&#xff0c;甚至在顶级期刊AAAI上发表过强化学习在王者荣耀中应用的论文。 什么…

BEVDet4D 论文学习

1. 解决了什么问题&#xff1f; 单帧数据包含的信息很有限&#xff0c;制约了目前基于视觉的多相机 3D 目标检测方法的性能&#xff0c;尤其是关于速度预测任务&#xff0c;要远落后于基于 LiDAR 和 radar 的方法。 2. 提出了什么方法&#xff1f; BEVDet4D 将 BEVDet 方法从…

C++ Vecter

C Vecter &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了C中vector的介绍以及相关的一些接口的使用 …

Prometheus+Grafana监控系统

一、简介 1、Prometheus简介 官网&#xff1a;https://prometheus.io 项目代码&#xff1a;https://github.com/prometheus Prometheus&#xff08;普罗米修斯&#xff09;是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目&#xff0c;拥有非常活跃的开发人员…

第二章 Electron自定义界面(最大化、最小化、关闭、图标等等)

一、介绍 &#x1f606; &#x1f601; &#x1f609; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需…