Hadoop-32 ZooKeeper 分布式锁问题 分布式锁Java实现 附带案例和实现思路代码
创始人
2025-01-10 02:08:43
0

章节内容

上节我们完成了:

  • ZooKeeper的Leader选举机制
  • ZooKeeper的选举过程
  • ZooKeeper的ZAB协议

背景介绍

这里是三台公网云服务器,每台 2C4G,搭建一个Hadoop的学习环境,供我学习。
之前已经在 VM 虚拟机上搭建过一次,但是没留下笔记,这次趁着前几天薅羊毛的3台机器,赶紧尝试在公网上搭建体验一下。

  • 2C4G 编号 h121
  • 2C4G 编号 h122
  • 2C2G 编号 h123

分布式锁

出现问题1(单机器)

  • 假设 Redis 里面的某个商品库存为1,此时两个用户同时下单,其中一个下单请求执行到第3步,更新数据库的库存为0,但是第4步还没执行。
  • 而另外一个用户下单执行到了第二步,发现库存还是1,就会继续执行第3步。
  • 但是此时库存已经为0了,所以数据库没有限制,此时会出现超卖的问题。
    在这里插入图片描述

解决方案1

  • 用锁把2、3、4步锁住,让他们执行完后,另一个线程才能够继续执行。
  • 但是由于业务发展迅速,原来的单机已经不能够满足,此时增加一台机器后,会出现更严重的问题。
    在这里插入图片描述

出现问题2(多机器)

假设有两个订单同时执行,分别有两个机器执行,那么这两个请求就是可以同时执行了,这样就依然出现了超卖的问题。

在这里插入图片描述

解决方案2

我们需要使用分布式锁来解决上面出现的问题。
分布式锁的作用就是在整个系统中提供一个全局的、唯一的锁,在分布式系统中每个系统进行相关的操作时都需要获取到该锁,才能够执行相应的操作。

ZK 分布式锁

实现思路

  • 锁就是ZK指定目录下序号最小的临时节点,多个系统的多个线程都要在此目录下创建临时顺序节点,因为ZK会保证节点的顺序性,所以可以利用节点的顺序性进行锁判断。
  • 每个线程都是先创建临时顺序节点,然后获取当前目录下最小的节点(序号),判断最小节点是不是当前节点,如果是那么获取锁成功,如果不是则获取锁失败。
  • 获取锁失败的线程获取当前节点上一个临时顺序节点,并对此节点进行监听,当该节点删除时,代表释放了锁。

流程图

在这里插入图片描述

编写代码

LockTest

package icu.wzk.zk.demo02;  public class LockTest {      public static void main(String[] args) {         for (int i = 0; i < 10; i ++) {             // 启动10个             new Thread(new LockRunnable()).start();         }     }      static class LockRunnable implements Runnable {          @Override         public void run() {             final ClientTest clientTest = new ClientTest();             clientTest.getLock();             try {                 Thread.sleep(2000);             } catch (InterruptedException e) {                 e.printStackTrace();             }             clientTest.deleteLock();         }     }  }  

ClientTest

package icu.wzk.zk.demo02;  import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient;  import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch;  public class ClientTest {      private ZkClient zkClient = new ZkClient("h121.wzk.icu:2181,h122.wzk.icu:2181,h123.wzk.icu:2181");      String beforeNodePath;      String currentNodePath;      CountDownLatch countDownLatch = null;      public ClientTest() {         synchronized (ClientTest.class) {             if (!zkClient.exists("/lock")) {                 zkClient.createPersistent("/lock");             }         }     }      public boolean tryGetLock() {         if (null == currentNodePath || currentNodePath.isEmpty()) {             currentNodePath = zkClient.createEphemeralSequential("/lock/", "lock");         }         final List childs = zkClient.getChildren("/lock");         Collections.sort(childs);         final String minNode = childs.get(0);         if (currentNodePath.equals("/lock/" + minNode)) {             return true;         } else {             final int i = Collections.binarySearch(childs, currentNodePath.substring("/lock/".length()));             String lastNodeChild = childs.get(i - 1);             beforeNodePath = "/lock/" + lastNodeChild;         }         return false;     }      public void waitForLock() {         final IZkDataListener iZkDataListener = new IZkDataListener() {             @Override             public void handleDataChange(String dataPath, Object data) throws Exception {                 //             }              @Override             public void handleDataDeleted(String dataPath) throws Exception {                 countDownLatch.countDown();             }         };         zkClient.subscribeDataChanges(beforeNodePath, iZkDataListener);          if (zkClient.exists(beforeNodePath)) {             countDownLatch = new CountDownLatch(1);             try {                 countDownLatch.await();             } catch (InterruptedException e) {                 e.printStackTrace();             }         }          zkClient.unsubscribeDataChanges(beforeNodePath, iZkDataListener);     }      public void deleteLock() {         if (zkClient != null) {             zkClient.delete(currentNodePath);             zkClient.close();         }     }      public void getLock() {         final String threadName = Thread.currentThread().getName();         if (tryGetLock()) {             System.out.println(threadName + ": 获取到了锁!");         } else {             System.out.println(threadName + ": 没有获取到锁!");             waitForLock();             // 自己调用自己             getLock();         }     }   }  

运行结果

在这里插入图片描述

相关内容

热门资讯

第八分钟总结!欢乐对决破解版,... 第八分钟总结!欢乐对决破解版,新518互娱脚本下载(辅助)一贯是有修改器(哔哩哔哩)1、新518互娱...
第七分钟要领!小程序卡五星辅助... 第七分钟要领!小程序卡五星辅助,随意玩游戏平台官方挂开挂(辅助)本来是真的软件(哔哩哔哩)该软件可以...
两分钟积累!吉祥填大坑脚本,h... 两分钟积累!吉祥填大坑脚本,h5大厅反杀教程(辅助)一直是有工具(哔哩哔哩)吉祥填大坑脚本脚本下载中...
一分钟操作!吉祥填大坑有插件吗... 一分钟操作!吉祥填大坑有插件吗,新西部透视辅助(辅助)竟然存在有辅助器(哔哩哔哩)1、不需要AI权限...
九分钟积累!潮汕激k辅助,微信... 九分钟积累!潮汕激k辅助,微信开心十三张脚本(辅助)本来真的是有软件(哔哩哔哩)微信开心十三张脚本能...
一分钟方案!南宁友乐辅助,久久... 一分钟方案!南宁友乐辅助,久久大厅挂价格(辅助)好像存在有软件(哔哩哔哩)进入游戏-大厅左侧-新手福...
第二分钟绝活!蘑菇云游破解版,... 第二分钟绝活!蘑菇云游破解版,财神十三章张助安装包(辅助)切实有挂下载(哔哩哔哩)小薇(辅助器软件下...
第六分钟练习!多乐辅助在哪里下... 第六分钟练习!多乐辅助在哪里下载,新老夫子脚本(辅助)切实有挂辅助(哔哩哔哩)1、用户打开应用后不用...
第八分钟办法!广东闲来游戏辅助... 第八分钟办法!广东闲来游戏辅助,新天道大厅辅助(辅助)真是真的有修改器(哔哩哔哩)1、广东闲来游戏辅...
第4分钟妙招!牵手游戏辅助软件... 第4分钟妙招!牵手游戏辅助软件,樱花之盛有挂吗(辅助)切实存在有神器(哔哩哔哩)1、任何牵手游戏辅助...