Zookeeper怎么实现分布式锁?
对访问资源 R1 的过程加锁,在操作 O1 结束对资源 R1 访问前,其他操作不允许访问资源 R1。以上算是对独占锁的简单定义了,那么这段定义在 Zookeeper 的“类 Unix/Linux 文件系统”的结构中是怎样实现的呢?在锁答案前,我们先看张图:
图1 独占锁的 Zookeeper 节点结构
如上图,对于独占锁,我们可以将资源 R1 看做是 lock 节点,操作 O1 访问资源 R1 看做创建 lock 节点,释放资源 R1 看做删除 lock 节点。这样我们就将独占锁的定义对应于具体的 Zookeeper 节点结构,通过创建 lock 节点获取锁,删除节点释放锁。详细的过程如下:
1、多个客户端竞争创建 lock 临时节点
2、其中某个客户端成功创建 lock 节点,其他客户端对 lock 节点设置 watcher
3、持有锁的客户端删除 lock 节点或该客户端崩溃,由 Zookeeper 删除 lock 节点
4、其他客户端获得 lock 节点被删除的通知
5、重复上述4个步骤,直至无客户端在等待获取锁了
上面即独占锁具体的实现步骤,理解起来并不复杂,这里不再赘述。
图2 获取独占锁流程图
2.2 读写锁的实现
说完独占锁的实现,这节来说说读写锁的实现。读写锁包含一个读锁和写锁,操作 O1 对资源 R1 加读锁,且获得了锁,其他操作可同时对资源 R1 设置读锁,进行共享读操作。
如果操作 O1 对资源 R1 加写锁,且获得了锁,其他操作再对资源 R1 设置不同类型的锁都会被阻塞。总结来说,读锁具有共享性,而写锁具有排他性。那么在 Zookeeper 中,我们可以用怎样的节点结构实现上面的操作呢?
图3 读写锁的 Zookeeper 节点结构
在 Zookeeper 中,由于读写锁和独占锁的节点结构不同,读写锁的客户端不用再去竞争创建 lock 节点。所以在一开始,所有的客户端都会创建自己的锁节点。如果不出意外,所有的锁节点都能被创建成功,此时锁节点结构如图3所示。之后,客户端从 Zookeeper 端获取 /share_lock 下所有的子节点,并判断自己能否获取锁。如果客户端创建的是读锁节点,获取锁的条件(满足其中一个即可)如下:
1、自己创建的节点序号排在所有其他子节点前面
2、自己创建的节点前面无写锁节点
如果客户端创建的是写锁节点,由于写锁具有排他性。所以获取锁的条件要简单一些,只需确定自己创建的锁节点是否排在其他子节点前面即可。
不同于独占锁,读写锁的实现稍微复杂一下。读写锁有两种实现方式,各有异同,接下来就来说说这两种实现方式。
读写锁的第一种实现
第一种实现是对 /sharelock 节点设置 watcher,当 /sharelock 下的子节点被删除时,未获取锁的客户端收到 /share_lock 子节点变动的通知。在收到通知后,客户端重新判断自己创建的子节点是否可以获取锁,如果失败,再次等待通知。详细流程如下:
1、所有客户端创建自己的锁节点
2、从 Zookeeper 端获取 /sharelock 下所有的子节点,并对 /sharelock 节点设置 watcher
3、判断自己创建的锁节点是否可以获取锁,如果可以,持有锁。否则继续等待
4、持有锁的客户端删除自己的锁节点,其他客户端收到 /share_lock 子节点变动的通知
5、重复步骤2、3、4,直至无客户端在等待获取锁了
上述步骤对于的流程图如下:
图4 获取读写锁实现1流程图
上面获取读写锁流程并不复杂,但却存在性能问题。以图3所示锁节点结构为例,第一个锁节点 host1-W-0000000001 被移除后,Zookeeper 会将 /share_lock 子节点变动的通知分发给所有的客户端。
但实际上,该子节点变动通知除了能影响 host2-R-0000000002 节点对应的客户端外,分发给其他客户端则是在做无用功,因为其他客户端即使获取了通知也无法获取锁。所以这里需要做一些优化,优化措施是让客户端只在自己关心的节点被删除时,再去获取锁。
读写锁的第二种实现
在了解读写锁第一种实现的弊端后,我们针对这一实现进行优化。这里客户端不再对 /share_lock 节点进行监视,而只对自己关心的节点进行监视。还是以图3的锁节点结构进行举例说明,host2-R-0000000002 对应的客户端 C2 只需监视 host1-W-0000000001 节点是否被删除即可。
而 host3-W-0000000003 对应的客户端 C3 只需监视 host2-R-0000000002 节点是否被删除即可,只有 host2-R-0000000002 节点被删除,客户端 C3 才能获取锁。而 host1-W-0000000001 节点被删除时,产生的通知对于客户端 C3 来说是无用的,即使客户端 C3 响应了通知也没法获取锁。Zookeeper 集群安装配置,超详细,速度收藏,推荐阅读。
这里总结一下,不同客户端关心的锁节点是不同的。如果客户端创建的是读锁节点,那么客户端只需找出比读锁节点序号小的最后一个的写锁节点,并设置 watcher 即可。而如果是写锁节点,则更简单,客户端仅需对该节点的上一个节点设置 watcher 即可。详细的流程如下:
1、所有客户端创建自己的锁节点
2、从 Zookeeper 端获取 /share_lock 下所有的子节点
3、判断自己创建的锁节点是否可以获取锁,如果可以,持有锁。否则对自己关心的锁节点设置 watcher
4、持有锁的客户端删除自己的锁节点,某个客户端收到该节点被删除的通知,并获取锁
5、重复步骤4,直至无客户端在等待获取锁了
上述步骤对于的流程图如下:
图5 获取读写锁实现2流程图
3. 写在最后
本文较为详细的描述了基于 Zookeeper 分布式锁的实现过程,并根据上面描述的两种锁原理实现了较为简单的分布式锁 demo,代码放在了 github 上,需要的朋友自取。
因为这只是一个简单的 demo,代码实现的并不优美,仅供参考。最后,如果你觉得文章还不错的话,欢迎点赞。如果有不妥的地方,也请提出来,我会虚心改之。
参考
《ZooKeeper 分布式过程协同技术详解》
《从Paxos到Zookeeper 分布式一致性原理与实践》
GitHub 代码:
https://github.com/code4wt/distributed_lock
关注Java技术栈微信公众号,在后台回复关键字:分布式,可以获取更多栈长整理的分布式架构技术干货。
最近干货分享
点击「阅读原文」和栈长学更多…
Zookeeper怎么实现分布式锁?的更多相关文章
- 如何用Zookeeper来实现分布式锁?
什么是Zookeeper临时顺序节点? 例如 : / 动物 植物 猫 仓鼠 荷花 松树 Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Zonde.# Znode分为四种类型 ...
- 基于zookeeper实现的分布式锁
基于zookeeper实现的分布式锁 2011-01-27 • 技术 • 7 条评论 • jiacheo •14,941 阅读 A distributed lock base on zookeeper ...
- java使用zookeeper实现的分布式锁示例
java使用zookeeper实现的分布式锁示例 作者: 字体:[增加 减小] 类型:转载 时间:2014-05-07我要评论 这篇文章主要介绍了java使用zookeeper实现的分布式锁示例,需要 ...
- ZooKeeper 笔记(6) 分布式锁
目前分布式锁,比较成熟.主流的方案有基于redis及基于zookeeper的二种方案. 大体来讲,基于redis的分布式锁核心指令为SETNX,即如果目标key存在,写入缓存失败返回0,反之如果目标k ...
- 基于Zookeeper实现多进程分布式锁
一.zookeeper简介及基本操作 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化.当对目录节点监控状态打开时,一旦目录节点的状态发生变化,Watc ...
- 利用ZooKeeper简单实现分布式锁
1.分布式锁的由来: 在程序开发过程中不得不考虑的就是并发问题.在java中对于同一个jvm而言,jdk已经提供了lock和同步等.但是在分布式情况下,往往存在多个进程对一些资源产生竞争关系,而这些进 ...
- 基于zookeeper简单实现分布式锁
https://blog.csdn.net/desilting/article/details/41280869 这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watc ...
- 基于zookeeper实现高性能分布式锁
实现原理:利用zookeeper的持久性节点和Watcher机制 具体步骤: 1.创建持久性节点 zkLock 2.在此父节点下创建子节点列表,name按顺序定义 3.Java程序获取该节点下的所有顺 ...
- zookeeper实现的分布式锁
在分布式系统中,多个jvm对共享资源进行操作时候,要加上锁,这就是分布式锁 利用zookeeper的临时节点的特性,可以实现分布式锁 public class ZookeeperDistrbuteLo ...
随机推荐
- 在Windows Server2016中安装SQL Server2016(转)
在Windows Server2016中安装SQL Server2016(转) 转自: http://blog.csdn.net/yenange/article/details/52980135 参考 ...
- MVC3中_ViewStart.cshtml的一些事
MVC3中,使用Razor模板引擎的话,会自动生成一个_ViewStart.cshtml文件. 很多人把这个文件当成类似Webform中的Master模板文件,其实这个_ViewStart.cshtm ...
- 软件测试工程师如何提高提BUG逼格
某个周四早上,沏好一杯茶,刚要坐到座位上,就听开发说,你们测试怎么提的Bug,给个截图能说明啥?截图上面显示的奔溃,如果是必现还好,如果不是必现,那么我们怎么去定位?至少给个日志吧?当时我的内心活动是 ...
- Rollei SL66 使用说明
根据记忆,并用不规范的语言描述我对sl66的使用心得:一.上卷1.用摇把顺时针转到12点位置,再退回3点位置:2.安插刀:3.后背上方按钮向右拨,打开后背:4.取出,装卷,再放入:5.转动后背上旋钮, ...
- zabbix--监控的组件和进程介绍
上图是zabbix的架构,zabbix proxy(代理),可以减小IO并发. zabbix web GUI是用php写的画图工具,从数据库抓取数据. zabbix database zabbix获取 ...
- 567. Permutation in String【滑动窗口】
Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. I ...
- transport error 202: bind failed: Address already in use
background: I have terminated some test debugger without properly saying goodbye. the JDWP didn't cl ...
- 现如今,最热门的13个Java微服务框架
曾经的 服务器领域 有许多不同的芯片架构???有哪些芯片架构???和操作系统???,经过长期发展,Java的“一次编译,到处运行”使得它在服务器领域找到一席之地,成为程序员们的最爱. 本文,我们将和大 ...
- “使用Adobe Reader XI打开PDF文件,左侧无法显示导航列表”解决方法
在Word中将文档另存为PDF格式之后,再使用Adobe Reader XI打开,没有左侧导航列表: 解决步骤: 1.在word另存为时,在另存为对话框中,点击如下图所示的“选项” 2.在弹出的对话框 ...
- centos WPS 字体安装
首先下载字体,解压后将整个wps_symbol_fonts目录拷贝到/usr/share/fonts目录下,然后赋予可读可执行权限. 权限设置操作如下: cd /usr/share/fonts/ ch ...