Zookeeper实现分布式锁(Zk分布式锁)

文章目录

概述

基于zookeeper临时有序节点可以实现的分布式锁。

1、zookeeper天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。

2、如果获取不到锁,只需要添加一个监听器就可以了,不用一直轮询,性能消耗较小。

3、如果有较多的客户端频繁的申请加锁、释放锁,对于zk集群的压力会比较大。

如何用Zookeeper实现分布式锁

使用 ZooKeeper 实现分布式锁是一种常见的方法,它可以确保在分布式系统中的多个节点上对共享资源进行互斥访问。下面是一种基本的方法来实现分布式锁:

  1. 创建一个持久性的父节点:
    在 ZooKeeper 中创建一个持久性的父节点,用于存储所有的锁。
  2. 每个请求尝试创建一个临时顺序节点:
    当一个节点需要获取锁时,它在上述创建的父节点下创建一个临时顺序节点。
  3. 获取节点列表:
    节点获取父节点下的所有子节点,并对它们进行排序。
  4. 判断是否是最小的节点:
    节点检查它是否是所有子节点中最小的节点。如果是,表示该节点获取了锁;否则,它监听比它小的前一个节点的删除事件。
  5. 如果不是最小的节点,则等待:
    如果节点不是最小的节点,它会监听比它小的前一个节点的删除事件,一旦前一个节点被删除,它再次尝试获取锁,重复步骤 3 和步骤 4。
  6. 释放锁:
    当节点使用完共享资源后,它删除自己创建的临时顺序节点,从而释放锁。
    这种方法利用了 ZooKeeper 的节点顺序性质和临时节点的特性来实现分布式锁。由于节点是按顺序创建的,所以可以通过比较节点的序号来确定锁的持有者。而且,使用临时节点可以确保如果锁的持有者发生故障或失去连接,则锁会被自动释放。
    这只是一个基本的实现方法,实际应用中可能还需要考虑超时处理、重试机制、错误处理等情况,以确保分布式锁的可靠性和健壮性。

Zk分布式锁原理和实现

Zookeeper 是基于临时顺序节点以及 Watcher 监听器机制实现分布式锁的。

1.ZooKeeper 的每一个节点都是一个天然的顺序发号器。

2.ZooKeeper 节点的递增有序性可以确保锁的公平。

3.ZooKeeper 的节点监听机制,可以保障占有锁的传递有序而且高效

Zookeeper实现分布式锁原理:

Zookeeper节点路径不能重复 保证唯一性。 临时节点+事件通知

1.获取锁方法:

多个jvm同时在zk上创建一个临时节点/lockPath,

最终只能够有一个jvm创建临时节点成功,如果能够创建

临时节点成功jvm 表示获取锁成功能够正常执行业务逻辑,

如果没有创建临时节点成功的jvm,则表示获取锁失败。

获取锁失败之后,可以采用不断重试策略,重试多次

获取锁失败之后,当前的jvm就进入到阻塞状态。

2.释放锁方法:

直接调用.close();释放锁

因为采用临时节点,当我们调用close()方法的时候

该临时节点会自动被删除。

其他没有获取到锁的jvm,就会从新进入到获取锁的状态。

3.被唤醒的方法:

被阻塞的jvm(没有获取锁成功的jvm),采用事件监听的方式

监听到节点已经被删除的情况下,则开始从新进入到获取锁的状态。

Zookeeper 实现分布式锁的方法比较多,我们可以使用有序节点来实现,

1、来看这个图,每个线程或进程在 Zookeeper 上的/lock 目录下创建一个临时有序的节点表示去抢占锁,所有创建的节点会按照先后顺序生成一个带有序编号的节点。

2、线程创建节点后,获取/lock 节点下的所有子节点,判断当前线程创建的节点是否是所有的节点的序号最小的。

3、如果当前线程创建的节点是所有节点序号最小的节点,则认为获取锁成功。

4、如果当前线程创建的节点不是所有节点序号最小的节点,则对节点序号的前个节点添加一个事件监听,当前一个被监听的节点释放锁之后,触发回调通知,从而再次去尝试抢占锁。

ZooKeeper 是一种分布式协调服务,它可以帮助分布式系统中的各个节点进行协调和通信。ZooKeeper 的协调机制是通过一种称为 "ZNode" 的数据结构来实现的。

在 ZooKeeper 中,每个节点都被称为一个 ZNode,它可以有子节点和关联的数据。ZNode 可以被视为一种目录结构,其中每个节点都有一个路径。通过这个路径,可以找到节点的数据。

当使用 ZooKeeper 实现分布式锁时,可以使用一种称为 "顺序节点" 的机制。顺序节点是一种特殊的 ZNode,它会在创建时自动分配一个唯一的顺序编号。这个编号可以用来解决分布式锁的问题。

假设我们有一个需要被协调的任务,可以让多个进程都去创建 ZooKeeper 中的同一家目录下的一个子节点。由于是顺序节点,每个进程创建的子节点都会被分配一个唯一的编号。当一个进程创建了编号最小的子节点时,就认为它获得了锁,可以执行任务。其他进程在创建子节点时会被阻塞,等待前一个进程释放锁。

这个过程中,只要有一台机器能够成功创建子节点并获得锁,就可以完成任务。其他机器会继续等待,直到锁被释放。这样可以保证只有一个进程能够执行任务,实现分布式锁的效果。

总之,ZooKeeper 提供了分布式协调的机制,可以通过顺序节点实现分布式锁的功能,使得分布式系统中的任务可以被协调执行。

Zookeeper实现分布式锁Java代码

基于 ZooKeeper 实现分布式锁的一般步骤如下:

  1. 创建一个持久性节点:
    在 ZooKeeper 中创建一个持久性节点,作为锁的父节点,所有的锁都将作为其子节点。

  2. 获取锁:
    当一个客户端需要获取锁时,它在锁的父节点下创建一个临时顺序节点。

  3. 获取所有子节点列表:
    客户端获取锁父节点下的所有子节点,并对它们进行排序。

  4. 判断是否获取锁:
    客户端检查是否自己创建的节点是所有子节点中序号最小的节点,如果是,则表示客户端成功获取到了锁。

  5. 如果未获取锁,则监听前一个节点:
    如果客户端创建的节点不是序号最小的节点,则客户端需要监听前一个节点的变化事件。

  6. 处理监听事件:
    如果前一个节点被删除(表示前一个客户端释放了锁),则客户端重复步骤 3 和步骤 4。

  7. 使用锁:
    客户端成功获取到锁后,可以执行需要互斥访问的代码。

  8. 释放锁:
    当客户端完成了对共享资源的访问后,需要删除自己创建的临时顺序节点,以释放锁。
    下面是一个简单的 Java 代码示例,演示了如何使用 ZooKeeper 实现分布式锁:

    import org.apache.zookeeper.*;

    public class DistributedLock implements Watcher {

     private ZooKeeper zooKeeper;
     private String lockPath;
     private String currentLockPath;
    
     public DistributedLock(String host, String lockPath) {
         try {
             this.zooKeeper = new ZooKeeper(host, 3000, this);
             this.lockPath = lockPath;
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
    
     public void lock() {
         try {
             currentLockPath = zooKeeper.create(lockPath + "/lock", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
             while (true) {
                 String minNode = getMinNode();
                 if (currentLockPath.equals(minNode)) {
                     return;
                 } else {
                     synchronized (this) {
                         wait();
                     }
                 }
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
    
     private String getMinNode() throws KeeperException, InterruptedException {
         String minNode = null;
         for (String node : zooKeeper.getChildren(lockPath, false)) {
             if (minNode == null || node.compareTo(minNode) < 0) {
                 minNode = node;
             }
         }
         return minNode;
     }
    
     public void unlock() {
         try {
             zooKeeper.delete(currentLockPath, -1);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
    
     @Override
     public void process(WatchedEvent event) {
         synchronized (this) {
             notifyAll();
         }
     }
    
     public static void main(String[] args) {
         String host = "localhost:2181";
         String lockPath = "/locks";
         DistributedLock lock = new DistributedLock(host, lockPath);
         lock.lock();
         System.out.println("获取到锁,执行任务...");
         // 在这里执行需要互斥访问的代码
         lock.unlock();
         System.out.println("释放锁,任务完成。");
     }
    

    }

这段代码实现了一个简单的分布式锁,使用 ZooKeeper 实现了锁的获取和释放,确保了对共享资源的互斥访问。

相关推荐
我一直在流浪23 分钟前
Kafka - 消费者程序仅消费一半分区消息的问题
分布式·kafka
张彦峰ZYF2 小时前
投资策略规划最优决策分析
分布式·算法·金融
processflow流程图4 小时前
分布式kettle调度平台v6.4.0新功能介绍
分布式
全栈开发圈4 小时前
干货分享|分布式数据科学工具 Xorbits 的使用
分布式
运维&陈同学6 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
时差9536 小时前
Flink Standalone集群模式安装部署
大数据·分布式·flink·部署
菠萝咕噜肉i7 小时前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
只因在人海中多看了你一眼10 小时前
分布式缓存 + 数据存储 + 消息队列知识体系
分布式·缓存
zhixingheyi_tian12 小时前
Spark 之 Aggregate
大数据·分布式·spark
求积分不加C14 小时前
-bash: ./kafka-topics.sh: No such file or directory--解决方案
分布式·kafka