当前位置:   article > 正文

基于zookeeper+springboot的方式实现分布式锁_springboot实现zookeeper分布式锁

springboot实现zookeeper分布式锁

目录

zookeeper+springboot实现分布式锁教程

一.什么是分布式锁

二.实现分布式锁的技术

 三.基于zookeeper实现分布式锁

1.场景分析

2.环境配置

3.编码实现 

4.遇到的问题


zookeeper+springboot实现分布式锁教程

一.什么是分布式锁

分布式系统中,存在着许多进程同时运转,而为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现分布式锁

分布式锁:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。

二.实现分布式锁的技术

  • 数据库:利用 数据库 的 唯一索引 实现。
  • Redis:利用 Redis 的 setnx 命令实现。
  • Zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。

 三.基于zookeeper实现分布式锁

1.场景分析

 

 在这里我们使用两个线程来模拟分布锁中的客户端,编写分布式锁类,通过测试要实现:

只有一个线程能够获取到锁,等到这个线程释放后另外一个线程才能拿到锁。

2.环境配置

zookeeper集群环境
一个简单的springboot环境

3.编码实现 

建议大家在实现之前可以先对zookeeper的一些API操作有一些了解,这些我在我的另外一篇文章做了详细的介绍,有需要的小伙伴可以移步去看看喔。

基于Springboot整合zookeeper实现对节点的创建、监听与判断https://blog.csdn.net/weixin_47025166/article/details/125425882?spm=1001.2014.3001.5502

1.创建一个简单的springboot工程,在pom.xml文件导入zookeeper依赖

  1. <!--引入对应的zookeeper -->
  2. <dependency>
  3. <groupId>org.apache.zookeeper</groupId>
  4. <artifactId>zookeeper</artifactId>
  5. <version>3.7.1</version>
  6. </dependency>

2.开启zookeeper集群中的客户端 (至少保证集群能够正常启动)

[root@zookeeper3 ~]# zkCli.sh

 3.编写DistributedLock(分布式锁)

  1. package com.canrioyuan.zookeepertest.zkcase2;
  2. import org.apache.zookeeper.*;
  3. import org.apache.zookeeper.data.Stat;
  4. import java.io.IOException;
  5. import java.util.Collections;
  6. import java.util.List;
  7. import java.util.concurrent.CountDownLatch;
  8. //分布锁
  9. public class DistributedLock {
  10. //设置zookeeper连接
  11. private final String connectString = "zookeeper1:2181,zookeeper2:2181,zookeeper3:2181";
  12. //设置超时时间
  13. private final int sessionTimeout = 2000;
  14. //声明zookeeper
  15. private final ZooKeeper zk;
  16. //CountDownLatch使用场景
  17. //线程计数器 用于线程执行任务,计数 等待线程结束
  18. private CountDownLatch countDownLatch = new CountDownLatch(1);
  19. private CountDownLatch waitLatch = new CountDownLatch(1);
  20. //定义该临时节点上一个节点的路径
  21. private String waitPath;
  22. //定义临时节点
  23. private String mode;
  24. public DistributedLock() throws IOException, InterruptedException, KeeperException {
  25. //获取连接
  26. zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
  27. @Override
  28. public void process(WatchedEvent watchedEvent) {
  29. //如果连接上zk的话便可以对countDownLatch进行释放
  30. if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
  31. countDownLatch.countDown();
  32. }
  33. //如果上一个节点进行了删除节点的操作后则可以对监听进行释放
  34. if(watchedEvent.getType()==Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){
  35. waitLatch.countDown();
  36. }
  37. }
  38. });
  39. //等待zk连接后才会继续往下执行
  40. countDownLatch.await();
  41. //判断根节点/locks是否存在
  42. Stat stat = zk.exists("/locks", false);
  43. int version = stat.getVersion();
  44. System.out.println(version+"111111");
  45. //如果节点不存在
  46. if (stat == null) {
  47. zk.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  48. }
  49. }
  50. //对zk加锁
  51. public void zkLock() {
  52. //创建节点(临时带序号的)
  53. try {
  54. mode = zk.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  55. //判断节点是否是最小的序号节点,如果是的话就获取到锁;如果不是,监听到他序号前一个节点
  56. List<String> children = zk.getChildren("/locks", false);
  57. //用于判断children中的值
  58. //如果只有一个值,你就直接获取锁;如果有多个节点,则需要判断谁最小
  59. if (children.size() == 1) {
  60. return;
  61. } else {
  62. //对获取到的节点进行排序方便持续获取节点
  63. Collections.sort(children);
  64. //获取节点的名称 截取掉节点的前缀
  65. String thisNode = mode.substring("/locks/".length());
  66. //通过该节点的名称获取该节点在集合中的位置
  67. int index = children.indexOf(thisNode);
  68. System.out.println(index+"11111111112");
  69. //对节点所在的索引进行判断
  70. if (index == -1) {
  71. System.out.println("数据出现错误");
  72. } else if (index == 0) {
  73. //只有一个节点可以直接获取锁
  74. return;
  75. } else {
  76. //需要监听他前一个节点的变化
  77. waitPath = "/locks/" + children.get(index - 1);
  78. //通过获取前一个节点的路径对这个节点进行监听
  79. zk.getData(waitPath, true, null);
  80. //等待监听
  81. waitLatch.await();
  82. //监听结束后获得锁
  83. return;
  84. }
  85. }
  86. } catch (KeeperException e) {
  87. e.printStackTrace();
  88. } catch (InterruptedException e) {
  89. e.printStackTrace();
  90. }
  91. }
  92. //对zk解锁
  93. public void unZkLock() {
  94. try {
  95. zk.delete(mode,0);
  96. } catch (InterruptedException e) {
  97. e.printStackTrace();
  98. } catch (KeeperException e) {
  99. e.printStackTrace();
  100. }
  101. //删除节点
  102. }
  103. }

4.编写测试类DistributedLockTest

  1. package com.canrioyuan.zookeepertest.zkcase2;
  2. import org.apache.zookeeper.KeeperException;
  3. import java.io.IOException;
  4. public class DistributedLockTest {
  5. public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
  6. final DistributedLock lock1 = new DistributedLock();
  7. final DistributedLock lock2 = new DistributedLock();
  8. new Thread(new Runnable() {
  9. @Override
  10. public void run() {
  11. try {
  12. lock1.zkLock();
  13. System.out.println("线程1启动,获取到锁");
  14. Thread.sleep(5 * 1000);
  15. lock1.unZkLock();
  16. System.out.println("线程1释放锁");
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. }).start();
  22. new Thread(new Runnable() {
  23. @Override
  24. public void run() {
  25. try {
  26. lock2.zkLock();
  27. System.out.println("线程2启动,获取到锁");
  28. Thread.sleep(5 * 1000);
  29. lock2.unZkLock();
  30. System.out.println("线程2释放锁");
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. }).start();
  36. }
  37. }

5.启动测试,观察结果 

线程1先获取到锁

线程1执行完业务,释放锁 ;线程2获取到锁

 线程2释放锁

至此,我们分布式锁运行成功!!

4.遇到的问题

ConnectionLossException: KeeperErrorCode = ConnectionLoss for / 

因为我之前把连接的字符串设置成IP地址导致的报错,我们必须使用主机名

 解决步骤:

1.进入linux的hosts文件修改映射

[root@zookeeper2 /]# vi /etc/hosts

在以下代码中增加对应的主机映射 

2.修改每一台虚拟机的zoo.cfg

[root@zookeeper2 /]# vi /opt/module/zookeeper/conf/zoo.cfg

修改成对应的映射 

 3.修改DistributedLock中的connectString

这是我在运行中遇到的问题,大家一定要注意i 

至此,我们zookeeper+Springboot实现分布式锁的教程就结束啦~

感谢您的阅读,希望我的文章能给你带来帮助!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/54002
推荐阅读
相关标签
  

闽ICP备14008679号