基于临时序号节点来实现分布式锁

为什么要用临时节点呢?如果拿到锁的服务宕机了,会话失效ZK自己也会删除掉临时的序号节点,这样也不会阻塞其他服务。

流程:

1.在一个持久节点下面创建临时的序号节点作为锁节点,如:/lock/lockId00000001 /lock/lockId00000002

2.获取持久节点下面所有子节点,判断其最小的是不是自己,如果是自己则表示获取锁成功。

3.如果最小的结点不是自己,则阻塞等待,并对lock结点添加监听,如果结点数发生变化了,则说明有释放了锁。但是这里如果存在大量监听,当结点发生变化的时候,可能就会出现羊群效应。因为大家都监听了,同时会通知很多客户端,会造成ZK性能突然下降。

所以这里可以只监听自己前面的那个节点,排队执行,03监听02,02监听01

4.当锁释放,节点监听到变化之后,执行第2步。

释放锁只需要删除对应的临时节点,如果获取到锁的服务宕机了,因为是临时节点也会自己删除的。

代码实现:

  1. package com.nijunyang.zookeeper.zklock;
  2.  
  3. import lombok.Data;
  4. import org.I0Itec.zkclient.IZkDataListener;
  5. import org.I0Itec.zkclient.ZkClient;
  6.  
  7. import java.util.List;
  8. import java.util.stream.Collectors;
  9.  
  10. /**
  11. * Description:
  12. * Created by nijunyang on 2020/11/29 21:51
  13. */
  14. public class ZKLock {
  15. private static final String SERVER = "192.168.0.67:2181";
  16. private ZkClient zkClient;
  17. private static final String ROOT_PATH = "/lock";
  18.  
  19. public ZKLock() {
  20. zkClient = new ZkClient(SERVER, 5000, 20000);
  21. buildRoot();
  22. }
  23.  
  24. private void buildRoot() {
  25. if (!zkClient.exists(ROOT_PATH)) {
  26. zkClient.createPersistent(ROOT_PATH);
  27. }
  28. }
  29.  
  30. /**
  31. * 加锁
  32. *
  33. * @param lockId
  34. * @param timeout
  35. * @return
  36. */
  37. public Lock lock(String lockId, long timeout) {
  38. Lock lockNode = createLock(lockId);
  39. // 尝试激活锁
  40. tryActiveLock(lockNode);
  41. if (!lockNode.isActive()) {
  42. try {
  43. synchronized (lockNode) {
  44. lockNode.wait(timeout);
  45. }
  46. } catch (InterruptedException e) {
  47. throw new RuntimeException(e);
  48. }
  49. }
  50. if (!lockNode.isActive()) {
  51. throw new RuntimeException("获取锁超时");
  52. }
  53. return lockNode;
  54. }
  55.  
  56. /**
  57. * 释放锁
  58. *
  59. * @param lock
  60. */
  61. public void unlock(Lock lock) {
  62. if (lock.isActive()) {
  63. zkClient.delete(lock.getPath());
  64. }
  65. }
  66.  
  67. /**
  68. * 激活锁
  69. * @param lockNode
  70. */
  71. private void tryActiveLock(Lock lockNode) {
  72. // 判断当前是否为最小节点
  73. List<String> list = zkClient.getChildren(ROOT_PATH)
  74. .stream()
  75. .sorted()
  76. .map(p -> ROOT_PATH + "/" + p)
  77. .collect(Collectors.toList());
  78. String firstNodePath = list.get(0);
  79.  
  80. //第一个节点是当前节点,将锁设置为激活
  81. if (firstNodePath.equals(lockNode.getPath())) {
  82. lockNode.setActive(true);
  83. } else {
  84. //第一个节点不是当前节点,则监听前面一个节点
  85. String upNodePath = list.get(list.indexOf(lockNode.getPath()) - 1);
  86. zkClient.subscribeDataChanges(upNodePath, new IZkDataListener() {
  87. @Override
  88. public void handleDataChange(String dataPath, Object data) throws Exception {
  89. }
  90. @Override
  91. public void handleDataDeleted(String dataPath) throws Exception {
  92. //监听之后继续尝试加锁,加锁成功唤醒之前的等待
  93. tryActiveLock(lockNode);
  94. synchronized (lockNode) {
  95. if (lockNode.isActive()) {
  96. lockNode.notify();
  97. }
  98. }
  99. zkClient.unsubscribeDataChanges(upNodePath, this);
  100. }
  101. });
  102. }
  103. }
  104. /**
  105. * 创建锁节点
  106. *
  107. * @param lockId
  108. * @return Lock
  109. */
  110. private Lock createLock(String lockId) {
  111. String nodePath = zkClient.createEphemeralSequential(ROOT_PATH + "/" + lockId, "write");
  112. return new Lock(lockId, nodePath);
  113. }
  114.  
  115. @Data
  116. public static class Lock {
  117.  
  118. private String lockId;
  119. private String path;
  120. /**
  121. * 是否激活锁
  122. */
  123. private boolean active;
  124.  
  125. public Lock(String lockId, String path) {
  126. this.lockId = lockId;
  127. this.path = path;
  128. }
  129. }
  130. }

Zookeeper(5)---分布式锁的更多相关文章

  1. zookeeper实现分布式锁服务

    A distributed lock base on zookeeper. zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hiv ...

  2. [ZooKeeper.net] 3 ZooKeeper的分布式锁

    基于ZooKeeper的分布式锁 ZooKeeper 里实现分布式锁的基本逻辑: 1.zookeeper中创建一个根节点(Locks),用于后续各个客户端的锁操作. 2.想要获取锁的client都在L ...

  3. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...

  4. zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  5. zookeeper 实现分布式锁安全用法

    zookeeper 实现分布式锁安全用法 标签: zookeeper sessionExpire connectionLoss 分布式锁 背景 ConnectionLoss 链接丢失 SessionE ...

  6. 基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  7. 转载 [ZooKeeper.net] 3 ZooKeeper的分布式锁

    [ZooKeeper.net] 3 ZooKeeper的分布式锁   基于ZooKeeper的分布式锁  源码分享:http://pan.baidu.com/s/1miQCDKk ZooKeeper ...

  8. Redis与Zookeeper实现分布式锁的区别

    Redis实现分布式锁 1.根据lockKey区进行setnx(set not exist,如果key值为空,则正常设置,返回1,否则不会进行设置并返回0)操作,如果设置成功,表示已经获得锁,否则并没 ...

  9. Zookeeper系列四:Zookeeper实现分布式锁、Zookeeper实现配置中心

    一.Zookeeper实现分布式锁 分布式锁主要用于在分布式环境中保证数据的一致性. 包括跨进程.跨机器.跨网络导致共享资源不一致的问题. 1. 分布式锁的实现思路 说明: 这种实现会有一个缺点,即当 ...

  10. 10分钟看懂!基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

随机推荐

  1. form表单ajax提交

    这里下面有两种  第一种是form表单里面添加了数据,并且含有上传的图片,第二种是from表单中不含有图片  只有普通数据 第一种form表单中包含有图片的类型: <form method=&q ...

  2. Canvas鼠标点击特效(富强、民主...)、收藏

    <script> /* 鼠标特效 */ var a_idx = 0; jQuery(document).ready(function($) { $("body").cl ...

  3. 关于mybatis拦截器,对结果集进行拦截

    因业务需要,需将结果集序列化为json返回,于是,网上找了好久资料,都是关于拦截参数的处理,拦截Sql语法构建的处理,就是很少关于对拦截结果集的处理,于是自己简单的写了一个对结果集的处理, 记录下. ...

  4. Spider--补充--Requests--session&cookie

    # session 与 cookie # 可能大家对session已经比较熟悉了,也大概了解了session的机制和原理,但是我们在做爬虫时如何会运用到session呢,就是接下来要讲到的会话保持. ...

  5. IP 层收发报文简要剖析6--ip_forward 报文转发

    //在函数ip_route_input_slow->ip_mkroute_input注册, /* * IP数据包的转发是由ip_forward()处理,该函数在ip_rcv_finish() * ...

  6. 04 . Vue组件注册,组件间数据交互,调试工具及组件插槽介绍及使用

    vue组件 组件(Component)是 Vue.js 最强大的功能之一. 组件可以扩展 HTML 元素,封装可重用的代码. 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的 ...

  7. Docker安装Oracle11g

    为什么使用docker安装oracle,因为自己搭建配置的话可能时间太久太繁琐等等原因,也因为docker实在太方便了 本文主要是使用docker-compose安装Oracle 11g,因为使用do ...

  8. day93:flask:

    目录 1.HTTP的会话控制 2.Cookie 3.Session 4.请求钩子 5.捕获错误 6.上下文:context 7.Flask-Script 1.HTTP的会话控制 1.什么是会话控制? ...

  9. 【芯片手册开发】Sil9136音频开发详细分析+源码实战

    目录 前言 参考 手册使用+实战 配置 Configuring Audio Using I2S 总结实现 前言 默认在开发了视频方面后 这方面的工作本来可以找技术支持拿个例程参考下,很快就可以的写出来 ...

  10. 企业级工作流解决方案(十二)--集成Abp和ng-alain--用户身份认证与权限验证

    多租户 如果系统需要支持多租户,那么最好事先定义好多租户的存储部署方式,Abp提供了几种方式,根据需要选择,每一个用户身份认证与权限验证都需要完全的隔离 这里设计的权限数据全部存储在缓存中,每个租户单 ...