有段时间没写博客了,在整理之前写过的一套自定义框架,并且整理好上传值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实现分布式锁相关推荐

  1. redis实现轮询算法_基于zookeeper或redis实现分布式锁

    前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...

  2. springboot mysql行锁_SpringBoot基于数据库实现简单的分布式锁

    本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...

  3. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  4. 什么是分布式锁?redis、zookeeper、etcd实现分布式锁有什么不同之处?

    目录 分布式锁定义 目的 基于redis分布式锁 基于zookeeper实现的分布式锁 edis.zookeeper.etcd实现分布式锁的比较 建议选择etcd实现分布式锁 分布式锁定义 分布式环境 ...

  5. 关于Zookeeper和Redis实现分布式锁的异同

    本文来说下Zookeeper和Redis实现分布式锁的异同 文章目录 概述 Redis单机实现分布式锁 Redis加锁 Redis解锁 Redis加锁过期时间设置问题 Zookeeper单机实现分布式 ...

  6. 基于注解的方式实现分布式锁

    基于注解的方式实现分布式锁 关于分布式锁的实现由两种 基于redis 基于zookeeper 为了方便分布式锁的使用, 基于注解的方式抽取成公用组件 DisLock注解 /*** 分布式锁的注解, 通 ...

  7. 基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性

    为了保证数据的争用安全,通常要采用锁机制控制. 如果是单应用部署,直接通过synchronized关键字修改方法,就能解决,但是如果是分布式的部署 该方法就不能解决这个问题啦,此时就引出了一个分布式锁 ...

  8. 基于Redis实现简单的分布式锁

    在分布式场景下,有很多种情况都需要实现最终一致性.在设计远程上下文的领域事件的时候,为了保证最终一致性,在通过领域事件进行通讯的方式中,可以共享存储(领域模型和消息的持久化数据源),或者做全局XA事务 ...

  9. Apache ZooKeeper - 使用ZK实现分布式锁(非公平锁/公平锁/共享锁 )

    文章目录 什么是分布式锁 分布式死锁 分类 排他锁 共享锁 实现 创建锁 获取锁 释放锁 Demo Jmeter配置 方案零 缺陷版本 方案一 非公平锁方案 缺陷 (羊群效应) 方案二 公平锁方案 方 ...

最新文章

  1. 1.lamp网站构建
  2. 使用LaunchScreen.storyboard黑屏
  3. 【转】android手势处理揭秘
  4. Win平台使用cmake工具生成sln工程示例
  5. (转)git常用命令
  6. vue路由详解版一目了然
  7. python编程加油_编程学习资料,中途加油站,c++/java/python/小程序/人工智能......等等等等...
  8. 为什么使用GB28181而不是直接rtsp拉流
  9. (转)淘淘商城系列——SSM框架整合之表现层整合
  10. 台式计算机usb口不能用,电脑USB接口没反应如何解决教程
  11. 计算机u盘病毒清除方式,清除文件夹exe病毒方法
  12. 西游记中托塔李天王的三个儿子,一个女儿和一个干女儿
  13. Vue知识点囊括清单
  14. UE-战斗无止境的复刻
  15. ireport 5.6.0 + Jasper 6.8.0 报表生成
  16. 酷睿i7 12700h参数 i712700h属于什么级别
  17. 吉首大学2019年程序设计竞赛(重现赛) 干物妹小埋(线段树求最长上升子序列)
  18. 从 firefox 缓存中提取视频
  19. CCF智能无人车比赛(国内绿洲科学实验云平台)心路历程+AWS Deepracer智能无人车比赛经验(附优秀代码re:lnvent 2018赛道)
  20. 常用的OCR文字识别软件有哪些

热门文章

  1. css阻止换行_CSS中,如何处理短内容和长内容?
  2. python textwrap_[Python标准库]textwrap——格式化文本段落
  3. java udp简单聊天程序_Java基于UDP协议实现简单的聊天室程序
  4. springmvc controller动态设置content-type
  5. JdbcTemplate使用小结
  6. 4am永远 鼠标按键设置_4AM称霸PCL和PEL 绝地求生与和平精英的双端冠军 | 电玩巴士...
  7. getline没有与参数列表匹配的重载函数_C++新增基础功能解析—函数重载功能的使用...
  8. html制作卡通图案代码,CSS画的卡通动画图案
  9. linux系统可以用迅雷吗,在Linux系统下使用wine运行迅雷5的方法
  10. 锁定计算机在哪里设置方法,怎样锁定电脑?如何设置电脑锁屏【步骤详解】