基于Zookeeper使用ZkClient实现分布式锁
有段时间没写博客了,在整理之前写过的一套自定义框架,并且整理好上传值github上了,也有一些新功能还在开发,欢迎大家使用:一个好用的Http接口请求工具组件
可能今天这篇文章跟之前的比有些跳跃性,一下子就谈到了Zookeeper了,不过也没关系啦,先谈谈最常用,然后在慢慢看Zooeeper的其他知识。
简单介绍
ZooKeeper致力于提供一个高性能、高可用,且具备严格的顺序访问控制能力的分布式协调服务,是雅虎公司创建,是Google的Chubby一个开源的实现,也是Hadoop和Hbase的重要组件。它的数据以树形结构(类似于文件系统)储存在内存当中由于数储存在内存当中(并且每个节点都必须要有数据),所以拿取数据效率特别快。
分布式锁:功能与之前并发编程中的Lock功能一致,主要是为了解决共享资源被竞争所导致的并发问题。由于并发编程当中锁是在当前的JVM当中,而对于分布式的服务来说单纯的JVM的锁已经不起作用了,不过实现功能还是一致。
监听机制
既然是锁,那么就存在线程等待以及线程被唤醒功能,所以就需要有一个监听机制,当ZooKeeper上的锁被释放之后需监听到,并且通知服务去获取锁资源,正好在ZooKeeper当中存在一种监听机制,为事件监听器(Watcher)
事件监听器:客户端可以在节点上注册监听器,当特定的事件发生后,ZooKeeper会通知到感兴趣的客户端;被监听的事件有:NodeCreated(节点创建)、NodeDeleted(节点删除)、NodeDataChanged(节点数据被改变)、NodeChildrenChange(子节点被修改)
Node类型
基于ZooKeeper分布式锁必然基于节点,在ZooKeeper创建节点共有四点类型:
1、持久化节点(PERSISENT): 同一个节点路径只能创建一个节点,并且连接创建节点后,断开连接后,节点仍然存在并且关闭服务会保存至磁盘上。
2、持久化顺序节点(PERSISENT_SEQUENTIAL):同一个节点路径可以创建多个节点,并且ZooKeeper会自动分配一个按顺序的节点号,断开连接后,节点仍然会保存至磁盘。
3、临时节点(EPHEMERAL):在一个连接中,同一路径下只能创建一个节点,当创建节点的连接关闭后,该节点会被删除,如果非正常关闭连接,则过一段时间后节点会被删除。
4、临时顺序节点(EPHEMERAL_SEQUENTIAL):同一路径下可以创建多个节点,但是节点名称ZooKeeper会自动分配一个按顺序的节点号,当连接关闭后,这些节点会被删除。
实现方式
既然是锁,那么必定是同一个节点,而且要先去尝试获取到锁,如果没有获取到,那么就进入等待,并且监听同一个节点是否被删除(或者修改),如果删除,则唤醒等待的线程,并且再次去获取ZooKeeper上的锁节点;那么整体的流程如下:
//锁节点
public static final String PATH = "/lock";
//尝试获取锁
public abstract boolean tryLock();
//等待锁释放
public abstract void waitLock();
//释放锁
public abstract void unLock();
//获取锁
void getLock(){if(tryLock()) {//获取到锁后,进行业务操作System.out.println(Thread.currentThread().getName() + " get Lock");}else {//没有获取则进入等待,并且监听锁节点是否被释放waitLock();//再次获取锁getLock();}
}
我这里是采用ZkClient进行操作ZooKeeper的,先创建一个ZkClient连接:
CountDownLatch latch = null;private static final String CONNECTION = "127.0.0.1:2181";ZkClient zkClient = new ZkClient(CONNECTION,3000);
先来看看尝试获取锁可以怎样实现:
@Override
public boolean tryLock() {try {//创建临时节点,也可以创建持久化节点,到时候释放节点的时候删除就好了zkClient.createEphemeral(PATH, "1".getBytes());return true;} catch (Exception e) {//如果创建失败,则获取节点锁失败,则进入等待return false;}
}
进入等待,并且监听锁节点是否删除或者修改:
@Override
public void waitLock() {//创建监听事件IZkDataListener listen = new IZkDataListener() {public void handleDataChange(String dataPath, Object data) throws Exception {//当前方法为监听节点修改,如果节点进行修改,那么就会执行当前方法}public void handleDataDeleted(String dataPath) throws Exception {//我这里是释放锁为删除节点,删除会执行当前方法latch.countDown();}};//注册监听器zkClient.subscribeDataChanges(PATH, listen);//如果ZooKeeper上存在锁节点,那么进入等待if(zkClient.exists(PATH)) {//采用CountDownLatch等待latch = new CountDownLatch(1);try {//进入等待latch.await();} catch (InterruptedException e) {e.printStackTrace();}}//删除监听器zkClient.unsubscribeDataChanges(PATH, listen);
}
然后就是释放节点了:
@Override
public void unLock() {if(zkClient != null) {System.out.println(Thread.currentThread().getName() + " unlock.. ");//删除节点zkClient.delete(PATH);//关闭当前连接zkClient.close();}
}
这么一套流程下来,分布式锁的功能就完成了,当这种实现的功能类似JVM锁中的非公平锁,即没有先后顺序所言,如果想要达到公平锁,那么就必须得使用顺序节点进行操作了。
那么分布式公平锁监听的节点就不是同一个节点了,而是监听当前节点的上一个节点:
private String lockSeq = null;private String before = null;@Override
public boolean tryLock() {if(!zkClient.exists(PATH)) {zkClient.createPersistent(PATH, true);}if(lockSeq == null) {lockSeq = zkClient.createEphemeralSequential(PATH + "/", "1".getBytes());}List<String> children = zkClient.getChildren(PATH);Collections.sort(children);if(lockSeq.equals(PATH + "/" + children.get(0))) {return true;}else {for(String str : children) {if(lockSeq.contains(str)) {break;}before = PATH + "/" + str;}System.out.println(Thread.currentThread().getName() + " before node:" + before);return false;}
}@Override
public void waitLock() {IZkDataListener listen = new IZkDataListener() {public void handleDataChange(String dataPath, Object data) throws Exception {}public void handleDataDeleted(String dataPath) throws Exception {latch.countDown();}};zkClient.subscribeDataChanges(before, listen);if(zkClient.exists(before)) {latch = new CountDownLatch(1);try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}}zkClient.unsubscribeDataChanges(before, listen);}@Override
public void unLock() {if(zkClient != null) {System.out.println(Thread.currentThread().getName() + " unlock.. ");System.out.println("this node:" + lockSeq + " last node:" + before);zkClient.delete(lockSeq);zkClient.close();}
}
实现的代码如上,大家可以各位去试一下,个人觉得非公平锁的效率相比公平锁来说效率要高一点点,不过对应大量的分布式服务去竞争锁资源的话,个人建议还是使用公平锁,避免阻塞时间过长。
基于Zookeeper使用ZkClient实现分布式锁相关推荐
- redis实现轮询算法_基于zookeeper或redis实现分布式锁
前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...
- springboot mysql行锁_SpringBoot基于数据库实现简单的分布式锁
本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...
- Zookeeper和Redis实现分布式锁,附我的可靠性分析
作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...
- 什么是分布式锁?redis、zookeeper、etcd实现分布式锁有什么不同之处?
目录 分布式锁定义 目的 基于redis分布式锁 基于zookeeper实现的分布式锁 edis.zookeeper.etcd实现分布式锁的比较 建议选择etcd实现分布式锁 分布式锁定义 分布式环境 ...
- 关于Zookeeper和Redis实现分布式锁的异同
本文来说下Zookeeper和Redis实现分布式锁的异同 文章目录 概述 Redis单机实现分布式锁 Redis加锁 Redis解锁 Redis加锁过期时间设置问题 Zookeeper单机实现分布式 ...
- 基于注解的方式实现分布式锁
基于注解的方式实现分布式锁 关于分布式锁的实现由两种 基于redis 基于zookeeper 为了方便分布式锁的使用, 基于注解的方式抽取成公用组件 DisLock注解 /*** 分布式锁的注解, 通 ...
- 基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性
为了保证数据的争用安全,通常要采用锁机制控制. 如果是单应用部署,直接通过synchronized关键字修改方法,就能解决,但是如果是分布式的部署 该方法就不能解决这个问题啦,此时就引出了一个分布式锁 ...
- 基于Redis实现简单的分布式锁
在分布式场景下,有很多种情况都需要实现最终一致性.在设计远程上下文的领域事件的时候,为了保证最终一致性,在通过领域事件进行通讯的方式中,可以共享存储(领域模型和消息的持久化数据源),或者做全局XA事务 ...
- Apache ZooKeeper - 使用ZK实现分布式锁(非公平锁/公平锁/共享锁 )
文章目录 什么是分布式锁 分布式死锁 分类 排他锁 共享锁 实现 创建锁 获取锁 释放锁 Demo Jmeter配置 方案零 缺陷版本 方案一 非公平锁方案 缺陷 (羊群效应) 方案二 公平锁方案 方 ...
最新文章
- 1.lamp网站构建
- 使用LaunchScreen.storyboard黑屏
- 【转】android手势处理揭秘
- Win平台使用cmake工具生成sln工程示例
- (转)git常用命令
- vue路由详解版一目了然
- python编程加油_编程学习资料,中途加油站,c++/java/python/小程序/人工智能......等等等等...
- 为什么使用GB28181而不是直接rtsp拉流
- (转)淘淘商城系列——SSM框架整合之表现层整合
- 台式计算机usb口不能用,电脑USB接口没反应如何解决教程
- 计算机u盘病毒清除方式,清除文件夹exe病毒方法
- 西游记中托塔李天王的三个儿子,一个女儿和一个干女儿
- Vue知识点囊括清单
- UE-战斗无止境的复刻
- ireport 5.6.0 + Jasper 6.8.0 报表生成
- 酷睿i7 12700h参数 i712700h属于什么级别
- 吉首大学2019年程序设计竞赛(重现赛) 干物妹小埋(线段树求最长上升子序列)
- 从 firefox 缓存中提取视频
- CCF智能无人车比赛(国内绿洲科学实验云平台)心路历程+AWS Deepracer智能无人车比赛经验(附优秀代码re:lnvent 2018赛道)
- 常用的OCR文字识别软件有哪些
热门文章
- css阻止换行_CSS中,如何处理短内容和长内容?
- python textwrap_[Python标准库]textwrap——格式化文本段落
- java udp简单聊天程序_Java基于UDP协议实现简单的聊天室程序
- springmvc controller动态设置content-type
- JdbcTemplate使用小结
- 4am永远 鼠标按键设置_4AM称霸PCL和PEL 绝地求生与和平精英的双端冠军 | 电玩巴士...
- getline没有与参数列表匹配的重载函数_C++新增基础功能解析—函数重载功能的使用...
- html制作卡通图案代码,CSS画的卡通动画图案
- linux系统可以用迅雷吗,在Linux系统下使用wine运行迅雷5的方法
- 锁定计算机在哪里设置方法,怎样锁定电脑?如何设置电脑锁屏【步骤详解】