返回顶部
首页 > 资讯 > 精选 >ZooKeeper的Curator分布式锁怎么实现
  • 301
分享到

ZooKeeper的Curator分布式锁怎么实现

2023-06-29 01:06:40 301人浏览 薄情痞子
摘要

本篇内容介绍了“ZooKeeper的Curator分布式锁怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Curator中有着更为标准

本篇内容介绍了“ZooKeeper的Curator分布式怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    Curator中有着更为标准、规范的分布式锁实现。与其我们自己去实现,不如直接使用Curator。通过学习Curator的源代码,我们也能了解实现分布式锁的最佳实践。

    Curator中有各种分布式锁,本文挑选其中一个---InterProceSSMutex进行讲解。

    我们先看一下Curator代码中对于InterProcessMutex的注释:

    可重入的互斥锁,跨JVM工作。使用ZooKeeper来控制锁。所有JVM中的任何进程,只要使用同样的锁路径,将会成为跨进程的一部分。此外,这个排他锁是“公平的”,每个用户按照申请的顺序得到排他锁。

    可见InterProcessMutex和我们自己实现的例子都是一个排他锁,此外还可以重入。 

      如何使用InterProcessMutex

    在分析InterProcessMutex代码前,我们先看一下它是如何使用的,下面代码简单展示了InterProcessMutex的使用:

        public static void soldTickWithLock(CuratorFramework client) throws Exception {        //创建分布式锁, 锁空间的根节点路径为/curator/lock        InterProcessMutex mutex = new InterProcessMutex(client, "/curator/locks");        mutex.acquire();         //获得了锁, 进行业务流程        //代表复杂逻辑执行了一段时间        int sleepMillis = (int) (Math.random() * 2000);        Thread.sleep(sleepMillis);         //完成业务流程, 释放锁        mutex.release();    }

    使用方式和我们自己编写的锁是一样的,首先通过mutex.acquire()获取锁,该方法会阻塞进程,直到获取锁,然后执行你的业务方法,最后通过 mutex.release()释放锁。

    接下来我们进入正题,展开分析Curator关于分布式锁的实现:

      实现思路

    Curator设计方式和之前我们自己实现的方式是类似的:

    创建有序临时节点

    触发“尝试取锁逻辑”,如果自己是临时锁节点序列的第一个,则取得锁,获取锁成功。

    如果自己不是序列中第一个,则监听前一个锁节点变更。同时阻塞线程

    当前一个锁节点变更时,通过watcher恢复线程,然后再次到步骤2“尝试取锁逻辑”

    如下图所示:

    ZooKeeper的Curator分布式锁怎么实现

       代码实现概述

    Curator对于排它锁的顶层实现逻辑在InterProcessMutex类中,它对客户端暴露锁的使用方法,如获取锁和释放锁等。但锁的上述实现逻辑,是由他持有的LockInternals对象来具体实现的。LockInternals使用StandardLockInternalsDriver类中的方法来做一些处理。

    简单点解释,我们打个比方,Curator好比是一家公司承接各种业务,InterProcessMutex是老板,收到自己客户(client)的需求后,分配给自己的下属LockInternals去具体完成,同时给他一个工具StandardLockInternalsDriver,让他在做任务的过程中使用。如下图展示:

    ZooKeeper的Curator分布式锁怎么实现

    接下来我们将深入分析InterProcessMutex、LockInternals及StandardLockInternalsDriver类。

      InterProcessMutex源码分析

    InterProcessMutex类是curator中的排它锁类,客户端直接打交道的就是InterProcessMutex。所以我们从顶层开始,先分析InterProcessMutex。

      实现接口

    InterProcessMutex实现了两个接口:

    public class InterProcessMutex implements InterProcessLock, Revocable<InterProcessMutex>

    InterProcessLock是分布式锁接口,分布式锁必须实现接口中的如下方法:

    获取锁,直到锁可用

    public void acquire() throws Exception;

    在指定等待的时间内获取锁。

    public boolean acquire(long time, TimeUnit unit) throws Exception;

    释放锁

    public void release() throws Exception;

    当前线程是否获取了锁

    boolean isAcquiredInThisProcess();

    以上方法也是InterProcessMutex暴露出来,供客户端在使用分布式锁时调用。

    Revocable<T>,实现该接口的锁,锁是可以被撤销的。本编文章重点讲解锁的实现机制,关于撤销部分不做讨论。

      属性

    InterProcessMutex属性如下:

    类型名称说明
    LockInternalsinternals锁的实现都在该类中,InterProcessMutex通过此类的方法实现锁
    StringbasePath锁节点在zk中的根路径
    ConcurrentMap<Thread, LockData>threadData线程和自己的锁相关数据映射
    StringLOCK_NAME常量,值为"lock-"。表示锁节点的前缀

    它还有一个内部静态类LockData,也是threadData中保存的value,它定义了锁的相关数据,包括锁所属线程,锁的全路径,和该线程加锁的次数(InterProcessMutex为可重入锁)。代码如下:

    private static class LockData{    final Thread owningThread;    final String lockPath;    final AtomicInteger lockCount = new AtomicInteger(1);    private LockData(Thread owningThread, String lockPath)    {        this.owningThread = owningThread;        this.lockPath = lockPath;    }}

      构造方法

    InterProcessMutex有三个构造方法,根据入参不同,嵌套调用,最终调用的构造方法如下:

    InterProcessMutex(CuratorFramework client, String path, String lockName, int maxLeases, LockInternalsDriver driver){    basePath = PathUtils.validatePath(path);    internals = new LockInternals(client, driver, path, lockName, maxLeases);}

    可见构造方法最终初始化了两个属性,basePath被设置为我们传入的值 "/curator/lock",这是锁的根节点。此外就是初始化了internals,前面说过internals是真正实现锁功能的对象。真正干活的是internals。

    构造完InterProcessMutex对象后,我们看看它是如何工作的。

      方法

    InterProcessMutex实现InterProcessLock接口,关于分布式锁的几个方法都在这个接口中,我们看看InterProcessMutex是如何实现的。

      获得锁

    获得锁有两个方法,区别为是否限定了等待锁的时间长度。其实最终都是调用的私有方法internalLock()。不限定等待时长的代码如下:

    public void acquire() throws Exception{    if ( !internalLock(-1, null) )    {        throw new IOException("Lost connection while trying to acquire lock: " + basePath);    }}

    可以看到internalLock()返回false时,只可能因为连接超时,否则会一直等待获取锁。

    internalLock逻辑如下:

    • 取得当前线程在threadData中的lockData

    • 如果存在该线程的锁数据,说明是锁重入, lockData.lockCount加1,直接返回true。获取锁成功

    • 如果不存在该线程的锁数据,则通过internals.attemptLock()获取锁,此时线程被阻塞,直至获得到锁

    • 锁获取成功后,把锁的信息保存到threadData中。

    • 如果没能获取到锁,则返回false。

    完整代码如下:

    private boolean internalLock(long time, TimeUnit unit) throws Exception{        Thread currentThread = Thread.currentThread();    LockData lockData = threadData.get(currentThread);    if ( lockData != null )    {        // re-entering        lockData.lockCount.incrementAndGet();        return true;    }    String lockPath = internals.attemptLock(time, unit, getLocknodeBytes());    if ( lockPath != null )    {        LockData newLockData = new LockData(currentThread, lockPath);        threadData.put(currentThread, newLockData);        return true;    }    return false;}

    可以看到获取锁的核心代码是internals.attemptLock

      释放锁

    释放锁的方法为release(),逻辑如下:

    从threadData中取得当前线程的锁数据,有如下情况:

    不存在,抛出无此锁的异常

    存在,而且lockCount-1后大于零,说明该线程锁重入了,所以直接返回,并不在zk中释放。

    存在,而且lockCount-1后小于零,说明有某种异常发生,直接抛异常

    存在,而且lockCount-1等于零,这是无重入的正确状态,需要做的就是从zk中删除临时节点,通过internals.releaseLock(),不管结果如何,在threadData中移除该线程的数据。 

    InterProcessMutex小结

    分布式锁主要用到的是上面两个方法,InterProcessMutex还有些其他的方法,这里就不做具体讲解,可以自己看一下,实现都不复杂。

    通过对InterProcessMutex的讲解,相信我们已经对锁的获得和释放有了了解,应该也意识到真正实现锁的是LockInternals类。接下来我们将重点讲解LockInternals。

      LockInternals源码分析

    Curator通过zk实现分布式锁的核心逻辑都在LockInternals中,我们按获取锁到释放锁的流程为指引,逐步分析LockInternals的源代码。

      获取锁

    在InterProcessMutex获取锁的代码分析中,可以看到它是通过internals.attemptLock(time, unit, getLockNodeBytes());来获取锁的,那么我们就以这个方法为入口。此方法的逻辑比较简单,如下:

    通过driver在zk上创建锁节点,获得锁节点路径。

    通过internalLockLoop()方法阻塞进程,直到获取锁成功。

    核心代码如下:

    ourPath = driver.createsTheLock(client, path, localLockNodeBytes);hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);

    我们继续分析internalLockLoop方法,获取锁的核心逻辑在此方法中。

    internalLockLoop中通过while自旋,判断锁如果没有被获取,将不断的去尝试获取锁。

    while循环中逻辑如下:

    • 通过driver查看当前锁节点序号是否排在第一位,如果排在第一位,说明取锁成功,跳出循环

    • 如果没有排在第一位,则监听自己的前序锁节点,然后阻塞线程。

    当前序节点释放了锁,监听会被触发,恢复线程,此时主线程又回到while中第一步。

    重复以上逻辑,直至获取到锁(自己锁的序号排在首位)。

    internalLockLoop方法核心代码如下:

    while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock ){    List<String>        children = getSortedChildren();    String              sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash     PredicateResults    predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);    if ( predicateResults.getsTheLock() )    {        haveTheLock = true;    }    else    {        String  previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();         synchronized(this)        {            try             {                // use getData() instead of exists() to avoid leaving unneeded watchers which is a type of resource leak                client.getData().usingWatcher(watcher).forPath(previousSequencePath);                if ( millisToWait != null )                {                    millisToWait -= (System.currentTimeMillis() - startMillis);                    startMillis = System.currentTimeMillis();                    if ( millisToWait <= 0 )                    {                        doDelete = true;    // timed out - delete our node                        break;                    }                     wait(millisToWait);                }                else                {                    wait();                }            }            catch ( KeeperException.NoNodeException e )             {                // it has been deleted (i.e. lock released). Try to acquire again            }        }    }}

    获取锁的主要代码逻辑我们到这就已经分析完了,可见和我们自己的实现还是基本一样的。此外上面提到了driver对象,也就是StandardLockInternalsDriver类,它提供了一些辅助的方法,比如说在zk创建锁节点,判断zk上锁序列第一位是否为当前锁,锁序列的排序逻辑等。我们就不具体讲解了。

      释放锁

    释放锁的逻辑很简单,移除watcher,删除锁节点。代码如下:

    final void releaseLock(String lockPath) throws Exception{client.removeWatchers();revocable.set(null);deleteOurPath(lockPath);}

    “ZooKeeper的Curator分布式锁怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

    --结束END--

    本文标题: ZooKeeper的Curator分布式锁怎么实现

    本文链接: https://lsjlt.com/news/321708.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • ZooKeeper的Curator分布式锁怎么实现
      本篇内容介绍了“ZooKeeper的Curator分布式锁怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Curator中有着更为标准...
      99+
      2023-06-29
    • ZooKeeper框架教程Curator分布式锁实现及源码分析
      目录  如何使用InterProcessMutex  实现思路   代码实现概述  InterProcessMutex源码分析&nb...
      99+
      2024-04-02
    • ZooKeeper分布式锁的实现方式
      本篇内容介绍了“ZooKeeper分布式锁的实现方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录一、分布式锁方案比较二、ZooKeep...
      99+
      2023-06-20
    • 分析ZooKeeper分布式锁的实现
      目录一、分布式锁方案比较二、ZooKeeper实现分布式锁2.1、方案一2.2、方案二一、分布式锁方案比较 方案 ...
      99+
      2024-04-02
    • 基于Zookeeper怎么实现分布式锁
      这篇文章主要介绍“基于Zookeeper怎么实现分布式锁”,在日常操作中,相信很多人在基于Zookeeper怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”基于Zookeeper怎么实现分布式锁...
      99+
      2023-06-22
    • 怎么用springboot+zookeeper实现分布式锁
      本篇内容主要讲解“怎么用springboot+zookeeper实现分布式锁”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用springboot+zookeeper实现分布式锁”吧!Inte...
      99+
      2023-06-29
    • Zookeeper的分布式锁的实现方式
      这篇文章主要讲解了“Zookeeper的分布式锁的实现方式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Zookeeper的分布式锁的实现方式”吧!1. 背景最近在学习 Zookeeper,...
      99+
      2023-06-05
    • springboot整合curator实现分布式锁过程
      目录springboot curator实现分布式锁理论篇:实操篇:项目实际应用中分布式锁介绍锁的介绍悲观锁-数据库锁悲观锁-缓存锁分布式锁—zookeepersprin...
      99+
      2024-04-02
    • zookeeper分布式锁如何实现
      这篇文章主要介绍“zookeeper分布式锁如何实现”,在日常操作中,相信很多人在zookeeper分布式锁如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”zookeeper分布式锁如何实现”的疑惑有所...
      99+
      2023-06-27
    • Zookeeper如何实现分布式锁
      这篇“Zookeeper如何实现分布式锁”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Zookeeper如何实现分布式锁”文...
      99+
      2023-06-27
    • 使用Zookeeper实现分布式锁
      目录什么是临时顺序节点?Znode分为四种类型1.持久节点 (PERSISTENT)2.持久节点顺序节点(PERSISTENT_SEQUENTIAL)3.临时节点(EPHEMERAL...
      99+
      2022-11-13
      Zookeeper分布式锁 分布式锁 使用分布式锁
    • redis和zookeeper中怎么实现分布式锁
      redis和zookeeper中怎么实现分布式锁,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。   一、基于redis的分布...
      99+
      2024-04-02
    • InterProcessMutex实现zookeeper分布式锁原理
      原理简介: zookeeper实现分布式锁的原理就是多个节点同时在一个指定的节点下面创建临时会话顺序节点,谁创建的节点序号最小,谁就获得了锁,并且其他节点就会监听序号比自己小的节点,...
      99+
      2024-04-02
    • Java如何实现ZooKeeper分布式锁
      这篇文章主要介绍了Java如何实现ZooKeeper分布式锁,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是分布式锁在我们进行单机应用开发,涉及并发同步的时候,我们往往采...
      99+
      2023-06-29
    • 怎么使用curator进行分布式加锁
      本篇内容介绍了“怎么使用curator进行分布式加锁”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!多线程情况下对共享资源的操作需要加锁,避免...
      99+
      2023-06-02
    • ZooKeeper能否用于分布式锁的实现
      是的,ZooKeeper可以用于分布式锁的实现。ZooKeeper是一个分布式协调服务,可以用来实现分布式系统中的一些共享资源管理问...
      99+
      2024-03-07
      ZooKeeper
    • 基于Zookeeper实现分布式锁详解
      目录1、什么是Zookeeper?2、Zookeeper节点类型3、Zookeeper环境搭建4、Zookeeper基本使用5、Zookeeper应用场景6、Zookeeper分布式...
      99+
      2024-04-02
    • zookeeper实战之实现分布式锁的方法
      目录一、分布式锁的通用实现思路二、ZK实现分布式锁的思路三、ZK实现分布式锁的编码实现1、核心工具类实现2、测试代码编写线程安全问题复现使用上面封装的ZkLockHelper实现的分...
      99+
      2022-11-13
      zookeeper分布式锁 zookeeper实现分布式锁 zookeeper分布式锁原理
    • InterProcessMutex实现zookeeper分布式锁原理是什么
      这篇“InterProcessMutex实现zookeeper分布式锁原理是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇...
      99+
      2023-06-29
    • ZooKeeper中怎么处理分布式锁
      在ZooKeeper中处理分布式锁通常使用临时有序节点来实现。具体步骤如下: 在ZooKeeper的指定节点下创建一个顺序临时节点...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作