分布式锁原理与实战三:ZooKeeper分布式锁的原理

news2024/11/26 19:41:15
        

目录

ZooKeeper分布式锁的原理

ZooKeeper的每一个节点,都是一个天然的顺序发号器。

ZooKeeper节点的递增有序性,可以确保锁的公平

ZooKeeper的节点监听机制,可以保障占有锁的传递有序而且高效

ZooKeeper的节点监听机制,能避免羊群效应

分布式锁的抢占过程

客户端A发起一个加锁请求

客户端B过来排队

客户端B开启监听客户端A

客户端B抢锁成功

 

      

 


理解了经典的公平可重入锁的原理后,再来看在分布式场景下的公平可重入锁的原理。通过前面的分析,基本可以判定:ZooKeeper 的临时顺序节点,天生就有一副实现分布式锁的胚子。为什么呢?

ZooKeeper分布式锁的原理

ZooKeeper的每一个节点,都是一个天然的顺序发号器。

        在每一个节点下面创建临时顺序节点(EPHEMERAL_SEQUENTIAL )类型,新的子节点后面,会加上一个次序编号,而这个生成的次序编号,是上一个生成的次序编号加一。
        例如,有一个用于发号的节点 “/test/lock”  为父亲节点,可以在这个父节点下面创建相同前缀的临时顺序子节点,假定相同的前缀为 “/test/lock/seq-” 。第一个创建的子节点基本上应该为  /test/lock/seq-0000000000,下一个节点则为/test/lock/seq-0000000001,依次类推

ZooKeeper节点的递增有序性,可以确保锁的公平

        一个ZooKeeper   分布式锁,首先需要创建一个父节点,尽量是持久节点( PERSISTENT 类型),然后每个要获得锁的线程,都在这个节点下创建个临时顺序节点。由于ZK 节点,是按照创建的次序,依次递增的。
        为了确保公平,可以简单的规定:编号最小的那个节点,表示获得了锁。所以,每个线程在尝试占用锁之前,首先判断自己是排号是不是当前最小,如果是,则获取锁。

ZooKeeper的节点监听机制,可以保障占有锁的传递有序而且高效

        每个线程抢占锁之前,先尝试创建自己的 ZNode 。同样,释放锁的时候,就需要删除创建的 Znode 。创建成功后,如果不是排号最小的节点,就处于等待通知的状态。等谁的通知呢?不需要其他人,只需要等前一个 Znode 的通知就可以了。前一个 Znode  删除的时候,会触发  Znode  事件,当前节点能监听到删除事件,就是轮到了自己占有锁的时候。第一个通知第二个、第二个通知第三个,击鼓传花似的依次向后。
        ZooKeeper 的节点监听机制,能够非常完美地实现这种击鼓传花似的信息传递。具体的方法是,每一个等通知的Znode 节点,只需要监听( linsten )或者监视( watch )排号在自己前面那个,而且紧挨在自己前面的那个节点,就能收到其删除事件了。
        只要上一个节点被删除了,就进行再一次判断,看看自己是不是序号最小的那个节点,如果是,自己就获得锁。
        另外,ZooKeeper  的内部优越的机制,能保证由于网络异常或者其他原因,集群中占用锁的客户端失联时,锁能够被有效释放。一旦占用 Znode  锁的客户端与  ZooKeeper  集群服务器失去联系,这个临时 Znode 也将自动删除。排在它后面的那个节点,也能收到删除事件,从而获得锁。正是由于这个原因,在创建取号节点的时候,尽量创建临时 znode 节点。

ZooKeeper的节点监听机制,能避免羊群效应

        ZooKeeper 这种首尾相接,后面监听前面的方式,可以避免羊群效应。所谓羊群效应就是一个节点挂掉,所有节点都去监听,然后做出反应,这样会给服务器带来巨大压力,所以有了临时顺序节点,当一个节点挂掉,只有它后面的那一个节点才做出反应。   

分布式锁的抢占过程

        接下来我们一起来看看,多客户端获取及释放zk 分布式锁的整个流程及背后的原理。
        首先大家看看下面的图,如果现在有两个客户端一起要争抢zk上的一把分布式锁,会是个什么场景?
        如果大家对zk 还不太了解的话,建议先自行百度一下,简单了解点基本概念,比如 zk 有哪些节点类型等等。
        参见上图。zk 里有一把锁,这个锁就是 zk 上的一个节点。然后呢,两个客户端都要来获取这个锁,具体是怎么来获取呢?
        咱们就假设客户端A 抢先一步,对 zk 发起了加分布式锁的请求,这个加锁请求是用到了 zk 中的一个特殊的概念,叫做“ 临时顺序节点
        简单来说,就是直接在"my_lock" 这个锁节点下,创建一个顺序节点,这个顺序节点有 zk 内部自行维护的一个节点序号。

客户端A发起一个加锁请求

        比如说,第一个客户端来搞一个顺序节点,zk 内部会给起个名字叫做: xxx-000001 。然后第二个客户端来搞一个顺序节点,zk 可能会起个名字叫做: xxx-000002 。大家注意一下,最后一个数字都是依次递增的,从1 开始逐次递增。 zk 会维护这个顺序。
        所以这个时候,假如说客户端A 先发起请求,就会搞出来一个顺序节点,大家看下面的图,Curator框架大概会弄成如下的样子:
        大家看,客户端A 发起一个加锁请求,先会在你要加锁的 node 下搞一个临时顺序节点,这一大坨长长的名字都是Curator 框架自己生成出来的。
        然后,那个最后一个数字是"1" 。大家注意一下,因为客户端 A 是第一个发起请求的,所以给他搞出来的顺序节点的序号是"1"
        接着客户端A 创建完一个顺序节点。还没完,他会查一下"my_lock"这个锁节点下的所有子节点,并且这些子节点是按照序号排序的,这个时候他大概会拿到这么一个集合:
        接着客户端A 会走一个关键性的判断,就是说:唉!兄弟,这个集合里,我创建的那个顺序节点,是不是排在第一个啊?
        如果是的话,那我就可以加锁了啊!因为明明我就是第一个来创建顺序节点的人,所以我就是第一个尝试加分布式锁的人啊!
        bingo!加锁成功!大家看下面的图,再来直观的感受一下整个过程。

客户端B过来排队

        接着假如说,客户端A 都加完锁了,客户端 B过来想要加锁了,这个时候他会干一样的事儿:先是在"my_lock"这个锁节点下创建一个临时顺序节点,此时名字会变成类似于:

        大家看看下面的图:  

        客户端B 因为是第二个来创建顺序节点的,所以 zk 内部会维护序号为 "2"
        接着客户端B 会走加锁判断逻辑,查询"my_lock"锁节点下的所有子节点,按序号顺序排列,此时他看到的类似于:
        同时检查自己创建的顺序节点,是不是集合中的第一个?
        明显不是啊,此时第一个是客户端A 创建的那个顺序节点,序号为 "01" 的那个。所以加锁失败!

客户端B开启监听客户端A

        加锁失败了以后,客户端B 就会通过 ZK API 对他的顺序节点的上一个顺序节点加一个监听器。 zk 天然就可以实现对某个节点的监听。
        如果大家还不知道zk 的基本用法,可以百度查阅,非常的简单。客户端B的顺序节点是:

        他的上一个顺序节点,不就是下面这个吗? 

        即客户端A 创建的那个顺序节点!
        所以,客户端B会对下面这个节点加一个监听器,监听这个节点是否被删除等变化!大家看下面的图。

  

        接着,客户端A 加锁之后,可能处理了一些代码逻辑,然后就会释放锁。那么,释放锁是个什么过程呢?
        其实很简单,就是把自己在zk里创建的那个顺序节点,也就是将下面这个节点给删除。
        删除了那个节点之后,zk 会负责通知监听这个节点的监听器,也就是客户端 B 之前加的那个监听器,说:兄弟,你监听的那个节点被删除了,有人释放了锁。

        此时客户端B的监听器感知到了上一个顺序节点被删除,也就是排在他之前的某个客户端释放了锁。 

客户端B抢锁成功

        此时,就会通知客户端B重新尝试去获取锁,也就是获取"my_lock"节点下的子节点集合,此时为:

        集合里此时只有客户端B 创建的唯一的一个顺序节点了!
        然后呢,客户端B 判断自己居然是集合中的第一个顺序节点,bingo!可以加锁了!直接完成加锁,运行后续的业务代码即可,运行完了之后再次释放锁。

      

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

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

相关文章

STM32开发——定时器led、PWM呼吸灯

目录 1.定时器控制LED亮灭 2.PWM呼吸灯——定时器 1.定时器控制LED亮灭 定时器分类: 基本定时器(TIM6~TIM7) 通用定时器(TIM2~TIM5) 高级定时器(TIM1和TIM8) 通用定时器介绍: 16 …

jenkins接口自动化测试,allure报告怎么清楚上一个项目的用例报告?

持续集成(CI Continuous integration/CD Continuous Deployment)的含义其实是在研发过程中团队开发成员持续性的将他们的工作集成到一个完整流程中,通常每个成员每天至少集成一次,每次集成都通过自动化的构建(包括编译,发布&#…

【数据分享】1929-2022年全球站点的逐月平均降水量(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,说到常用的降水数据,最详细的降水数据是具体到气象监测站点的降水数据! 之前我们分享过1929-2022年全球气象站点的逐月平均气温、逐月最高气温…

【Windows】解决无线网卡TL-WN823N免驱版无法上网的问题

【Windows】解决无线网卡TL-WN823N免驱版无法上网的问题 1、背景2、解决办法3、查看适配器 1、背景 下午去前台领了一个"300M无线USB网卡"。 插到台式机上发现不能跳出WLAN网络信号。 我观察到每次插入无线上网卡,在window设置–>设备–>其他设…

员工资料导入

人事管理项目-员工资料导入 后端接口实现前端实现 既然有员工资料导出需求,当然也就有导入需求。对前端而言,员工资料导入就是文件上传,对后端而言,则是获取上传的文件进行解析,并把解析出来的数据保存到数据库中。 后…

Springboot实验二(用配置文件的方式整合Mybatis)仅供参考!

&#xff08;1)articleList.html 效果如下: <!DOCTYPE html> <html lang"en" xmlns:th"http://www.thymeleaf.org/"> <head> <meta charset"UTF-8"> <title>article 列表</title> </head> <body…

数论与组合数学 期末总结(未完

自然数的基本性质 数学归纳法(Principle of Mathematical Induction) n n 0 nn_{0} nn0​时成立&#xff0c;且 n k nk nk成立 ⇒ n k 1 \Rightarrow nk1 ⇒nk1成立&#xff0c;则定理对 n ≥ n 0 n\ge n_{0} n≥n0​成立良序定理(Well Ordering Principle) 每个非空集合…

网络编程 lesson7 广播组播和本地通信

目录 广播 什么是广播&#xff1f;&#xff08;了解&#xff09; 广播发送流程 广播接收流程 组播 什么是组播&#xff1f; 组播地址 组播结构体 组播发送流程 组播接收 本地套接字通信 什么是本地套接字通信&#xff1f; 特性 核心代码 程序实例 服务端 客户…

SpringCloud源码解析-gatewayopenFeign

SpringCloud高级应用-源码解析 1. gateway 源码解析1.1 自动装配1.2 核心装配1.2.1 GatewayClassPathWarningAutoConfiguration1.2.2 GatewayAutoConfiguration1.2.3 GatewayLoadBalancerClientAutoConfiguration1.2.4 GatewayRedisAutoConfiguration 1.3 Gateway 工作机制1.3.…

分布式任务调度XXL-JOB

XXL-JOB 分布式任务调度平台特点 职责分离&#xff0c;任务调度&#xff0c;任务执行解耦 执行一致性&#xff0c;任务执行不会多次重复执行 丰富的路由策略&#xff08;指定那个执行实例执行&#xff09; 阻塞处理 &#xff08;触发的任务&#xff0c;上一次没有执行完&am…

Android Studio类ChatGpt的免费AI编程助手

ChatGpt大火&#xff0c;带动了AI工具的发展&#xff0c;介绍两款免费的AI编程助手&#xff0c;一款用于输入关键字自动输出代码&#xff0c;一款则是自动补全提示&#xff0e; 可支持大部分代码编辑器&#xff0c;这里主要介绍Android Studio上安装使用&#xff0e; Bito 支…

来阿里面试,问我未来3-5年规划,我给领导画个大饼...

在面试的过程中是不是经常被面试官问未来几年的职业规划?你会答吗&#xff1f;是不是经常脑袋里一片空白&#xff0c;未来规划&#xff1f;我只是想赚更多的钱啊&#xff0c;哈哈哈&#xff0c;今天我来教大家&#xff0c;如何给面试官画一个大饼&#xff0c;让他吃的不亦乐乎…

c++day4 ——homework

1.思维导图 2. 整理类中特殊成员函数&#xff1a;构造函数&#xff0c;析构函数&#xff0c;拷贝构造函数&#xff0c;拷贝赋值函数的使用和实现 特殊成员函数的使用和实现&#xff1a; ① 构造函数 功能&#xff1a;当使用类实例化对象时&#xff0c;给类对象初始化空间以及初…

基于RK3399+FPGA的地面测试台多参数数据记录仪方案(一)硬件设计

地面测试台属于某型号数据记录仪的配套测试设备&#xff0c;主要工作包括&#xff1a;飞行前对记录 仪的功能检查&#xff0c;测试其工作状态和稳定性&#xff1b;实验结束后对已存储到记录仪中的数据进行 回读和进一步处理&#xff0c;通过数据分析得出导弹各项参数在飞行试…

苹果的首款“头显设备”Vision Pro在短期内必将被Meta Quest超越

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;Vision Pro是苹果在今年的WWDC2023开发者大会上发布的一款结合了增强现实(AR)和虚拟现实(VR)的“头显设备”&#xff0c;Vision Pro 的最终售价高达 3499 美元&#xff08;约合…

观察级水下机器人使用系列之二多普勒速度记录仪(DVL)

本文主要讲述观察级水下机器人所使用的多普勒速度记录仪器&#xff08;DVL&#xff09;&#xff0c;见下图。多普勒测速技术自1960年开始研究&#xff0c;1980年开始实现商业化&#xff0c;80年代中后期&#xff0c;窄带多普勒测速技术研究已日趋成熟&#xff0c;90年代以后&am…

初学者应该怎么学git-上

初学者应该怎么学git-上 Git 下载&安装 官网 地址: https://git-scm.com/ 下载版本: Git-2.33.0.2-64-bit.exe 下载慢&#xff0c;可以到镜像下载: http://npm.taobao.org/mirrors/git-for-windows/ 卸载 说明&#xff1a;如果安装过&#xff0c;可以卸载和老师版本…

详解Java中static的使用及其注意事项

1.可以用来修饰的结构&#xff1a; 主要用来修饰类的内部结构 属性、方法、代码块、内部类 2.static修饰属性&#xff1a;静态变量&#xff08;或类变量&#xff09; ​ 2.1 属性&#xff0c;是否使用static修饰&#xff0c;又分为&#xff1a;静态属性 vs 非静态属性(实例…

Yolov5更换上采样方式( 最近邻 / 双线性 / 双立方 / 三线性 / 转置卷积)

原文地址: https://www.iotword.com/3138.html 1. 常用上采样方式介绍 1. 1 最近邻插值(Nearest neighbor interpolation) >>> input torch.arange(1, 5, dtypetorch.float32).view(1, 1, 2, 2) >>> input tensor([[[[ 1., 2.],[ 3., 4.]]]])>>&g…

【goframe】(4):使用goframe 接入grpc服务,非常的方便,可以简单的构建和生成服务代码,并且启动方法也特别简单,使用代码本地调用成功

目录 前言1&#xff0c;关于grpc微服务2&#xff0c;修改生成代码3&#xff0c;相关的goframe的grpc配置4&#xff0c;总结 前言 本文的原文连接是: https://blog.csdn.net/freewebsys/article/details/108971807 未经博主允许不得转载。 博主CSDN地址是&#xff1a;https://b…