【Zookeekper】分布锁Curator
- 有序节点:假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;zookeeper提供了一个可选的有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号,也就是说如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,依次类推。
- 临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会自动删除该节点。
- 事件监听:在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zookeeper会通知客户端。当前zookeeper有如下四种事件:1)节点创建;2)节点删除;3)节点数据修改;4)子节点变更。
下面描述使用zookeeper实现分布式锁的算法流程,假设锁空间的根节点为/lock:
- 客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。
- 客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁;
- 执行业务代码;
- 完成业务流程后,删除对应的子节点释放锁。
步骤1中创建的临时节点能够保证在故障的情况下锁也能被释放,考虑这么个场景:假如客户端a当前创建的子节点为序号最小的节点,获得锁之后客户端所在机器宕机了,客户端没有主动删除子节点;如果创建的是永久的节点,那么这个锁永远不会释放,导致死锁;由于创建的是临时节点,客户端宕机后,过了一定时间zookeeper没有收到客户端的心跳包判断会话失效,将临时节点删除从而释放锁。
另外细心的朋友可能会想到,在步骤2中获取子节点列表与设置监听这两步操作的原子性问题,考虑这么个场景:客户端a对应子节点为/lock/lock-0000000000,客户端b对应子节点为/lock/lock-0000000001,客户端b获取子节点列表时发现自己不是序号最小的,但是在设置监听器前客户端a完成业务流程删除了子节点/lock/lock-0000000000,客户端b设置的监听器岂不是丢失了这个事件从而导致永远等待了?这个问题不存在的。因为zookeeper提供的API中设置监听器的操作与读操作是原子执行的,也就是说在读子节点列表时同时设置监听器,保证不会丢失事件。
最后,对于这个算法有个极大的优化点:假如当前有1000个节点在等待锁,如果获得锁的客户端释放锁时,这1000个客户端都会被唤醒,这种情况称为“羊群效应”;在这种羊群效应中,zookeeper需要通知1000个客户端,这会阻塞其他的操作,最好的情况应该只唤醒新的最小节点对应的客户端。应该怎么做呢?在设置事件监听时,每个客户端应该对刚好在它之前的子节点设置事件监听,例如子节点列表为/lock/lock-0000000000、/lock/lock-0000000001、/lock/lock-0000000002,序号为1的客户端监听序号为0的子节点删除消息,序号为2的监听序号为1的子节点删除消息。
所以调整后的分布式锁算法流程如下:
- 客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。
- 客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁;
- 执行业务代码;
- 完成业务流程后,删除对应的子节点释放锁。
Curator实现
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
public static void main(String[] args) throws Exception {
//创建zookeeper的客户端
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.newClient("10.21.41.181:2181,10.21.42.47:2181,10.21.49.252:2181", retryPolicy);
client.start(); //创建分布式锁, 锁空间的根节点路径为/curator/lock
InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock");
mutex.acquire();
//获得了锁, 进行业务流程
System.out.println("Enter mutex");
//完成业务流程, 释放锁
mutex.release(); //关闭客户端
client.close();
}
【Zookeekper】分布锁Curator的更多相关文章
- zk分布锁的java实现
只做记录,直接上代码 父类: package com.ylcloud.common.lock; import com.alibaba.fastjson.JSON; import org.I0Itec. ...
- Redis学习笔记~分布锁的使用
回到目录 分布锁主要用在多进程共同访问同一个资源时候,用来保持同一时间段只能有一个进程执行,同时避免了并发冲突的出现,这在很多场景都会用到,像秒杀库存,抽奖库存,多操作者处理一家公司等. void T ...
- 分布式锁没那么难,手把手教你实现 Redis 分布锁!|保姆级教程
书接上文 上篇文章「MySQL 可重复读,差点就让我背上了一个 P0 事故!」发布之后,收到很多小伙伴们的留言,从中又学习到很多,总结一下. 上篇文章可能举得例子有点不恰当,导致有些小伙伴没看懂为什么 ...
- ZooKeeper 分布式锁 Curator 源码 02:可重入锁重复加锁和锁释放
ZooKeeper 分布式锁 Curator 源码 02:可重入锁重复加锁和锁释放 前言 加锁逻辑已经介绍完毕,那当一个线程重复加锁是如何处理的呢? 锁重入 在上一小节中,可以看到加锁的过程,再回头看 ...
- ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁
前言 在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的? 并发加锁 先来看结果,在多线程对 /locks/lock_01 加锁时,是在后面又创建了新的临时节点. ...
- ZooKeeper 分布式锁 Curator 源码 04:分布式信号量和互斥锁
前言 分布式信号量,之前在 Redisson 中也介绍过,Redisson 的信号量是将计数维护在 Redis 中的,那现在来看一下 Curator 是如何基于 ZooKeeper 实现信号量的. 使 ...
- ZooKeeper 分布式锁 Curator 源码 01:可重入锁
前言 一般工作中常用的分布式锁,就是基于 Redis 和 ZooKeeper,前面已经介绍完了 Redisson 锁相关的源码,下面一起看看基于 ZooKeeper 的锁.也就是 Curator 这个 ...
- zookeeper实现分布锁
分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那一层来挡.当大量的行锁.表锁.事务充斥着数据库的时候.一般web应用很多的瓶颈都在数据库上,这里给大家介绍的是减轻数据库锁负担的一种 ...
- curator教程二——分布式锁
简介 在分布式环境下,为了防止多个服务同时修改同一个值,出现数据同步问题,通常用redis和zookeeper做分布式锁,在这里我们用zookeeper做分布式锁,并和单点环境中ReenTranL ...
随机推荐
- linux网络接口,struct ifreq struct ifconf结构
网络相关的ioctl请求的request参数及arg地址必须指向的数据类型如下表所示: 接口 SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFBRDADDR SI ...
- NOIP day1 玩具谜题
逻辑有一些复杂,但是理解之后就很简单.题目描述中mogician什么的太暴力了...-1s 按照题目描述模拟,就能满分. /* Au: GG * CCF NOIP2016 day1 * toy */ ...
- 彻底搞定C指针-函数名与函数指针
函数名与函数指针 一 通常的函数调用 一个通常的函数调用的例子://自行包含头文件 void MyFun(int x); //此处的申明也可写成:void MyFun( int ); int mai ...
- jmeter添加自定义扩展函数之Strng---base64解密
1,打开eclipse,新建maven工程,在pom中引用jmeter核心jar包,具体请看---https://www.cnblogs.com/guanyf/p/10863033.html---,这 ...
- asp.net mvc 特性路由(MapMvcAttributeRoutes)的应用
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012835032/article/details/51160824asp.net mvc 特性路由 ...
- 17. Jmeter-取样器一
jmeter-sampler介绍与使用 HTTP请求 Test Action Debug Sampler AJP/1.3 Sampler Access Log Sampler BeanShell Sa ...
- jQuery基础教程之is()方法和has() 方法
is()方法 —— 用于筛选 语法: jQueryObject.is( expr )返回值: is()函数的返回值为Boolean类型.true或者false.只要其中至少有一个元素符合给定的表达式就 ...
- Java并发AtomicLongArray类
java.util.concurrent.atomic.AtomicLongArray类提供了可以原子读取和写入的底层long类型数组的操作,并且还包含高级原子操作. AtomicLongArray支 ...
- UVA1629_Cake slicing
Cake slicing 给你一个矩形大小,和每个樱桃的坐标,现在让你去切使得切之后的小矩形包含一个樱桃,每次切的代价是切痕的长度,问你最小代价是多少 思路: 首先要明白一点,不能切除一个不含樱桃的矩 ...
- Unity中文本AssetBundle的解析
Unity在其安装目录下提供了许多实用的小工具,就存放在unity安装目录下的:Editor/Data/Tools, 其中该路径下的WebExtract.ext和binary2text.exe可以用 ...