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 实现了锁的获取和释放,确保了对共享资源的互斥访问。

相关推荐
lifallen8 小时前
Hadoop MapReduce 任务/输入数据 分片 InputSplit 解析
大数据·数据结构·hadoop·分布式·算法
Hello.Reader12 小时前
Kafka 4.0 从零到一8 步快速上手 + 实战要点与避坑
分布式·kafka
一叶飘零_sweeeet13 小时前
在分布式环境下正确使用MyBatis二级缓存
java·分布式·mybatis
设计师小聂!19 小时前
RabbitMQ详解
java·spring boot·分布式·rabbitmq·maven
退役小学生呀1 天前
十九、云原生分布式存储 CubeFS
分布式·docker·云原生·容器·kubernetes·k8s
smileNicky1 天前
Kafka 为什么具有高吞吐量的特性?
分布式·kafka
小白不想白a1 天前
【Hadoop】HDFS 分布式存储系统
hadoop·分布式·hdfs
随心............2 天前
Spark面试题
大数据·分布式·spark
Hello.Reader2 天前
用一根“数据中枢神经”串起业务从事件流到 Apache Kafka
分布式·kafka·apache
找不到、了2 天前
常用的分布式ID设计方案
java·分布式