使用Zookeeper实现分布式锁

 更新时间:2022年10月31日 09:04:18   作者:kongmin_123  
这篇文章主要介绍了使用Zookeeper实现分布式锁,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

如何用Zookeeper实现分布式锁?

在学习分布式锁之前,需要首先了解一下Zookeeper的[临时顺序节点]。

什么是临时顺序节点?

让我们来回顾一下Zookeeper节点的概念:

Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode。

Znode分为四种类型

1.持久节点 (PERSISTENT)

默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。

2.持久节点顺序节点(PERSISTENT_SEQUENTIAL)

所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:

3.临时节点(EPHEMERAL) 

和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。

4.临时顺序节点(EPHEMERAL_SEQUENTIAL) 

顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与Zookeeper断开连接后,临时节点会被删除。

那临时顺序节点和Zookeeper的分布式锁有什么关系呢?

Zookeeper分布式锁的原理

Zookeeper分布式锁恰恰应用了临时顺序节点。具体如何实现呢?让我们来看一看详细步骤:

获取锁

首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序节点 Lock1。

之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。 

这时候,如果再有一个客户端 Client2 前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock2。 

Client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。

于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。 

这时候,如果又有一个客户端Client3前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock3。 

Client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最小的。

于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。 

这样一来,Client1得到了锁,Client2监听了Lock1,Client3监听了Lock2。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock所依赖的AQS(AbstractQueuedSynchronizer)。

获得锁的过程大致就是这样,那么Zookeeper如何释放锁呢?

释放锁的过程很简单,只需要释放对应的子节点就好。

释放锁

释放锁分为两种情况:

1.任务完成,客户端显示释放

当任务完成时,Client1会显示调用删除节点Lock1的指令。

2.任务执行过程中,客户端崩溃

获得锁的Client1在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。 

由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。 

同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。 

最终,Client3成功得到了锁。 

使用Zookeeper实现分布式锁的大致流程就是这样。那么使用Zookeeper实现的分布式锁和Redis实现的分布式锁相比有什么优势和劣势呢?

下面总结一下他们各自的优劣

分布式锁优点缺点
Zookeeper

1.有封装好的框架,容易实现

2.有等待锁的队列,大大提升抢锁效率。

添加和删除节点性能较低
RedisSet和Del指令性能较高

1.实现复杂,需要考虑超时,原子性,误删等情形。

2.没有等待锁的队列,只能在客户端自旋来等待,效率低下。

有人说Zookeeper实现的分布式锁支持可重入,Redis实现的分布式锁不支持可重入,这是错误的观点。两者都可以在客户端实现可重入逻辑。

关于Zookeeper分布式锁的内容就介绍到这里啦。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 如何在Redis中实现分页排序查询过程解析

    如何在Redis中实现分页排序查询过程解析

    这篇文章主要介绍了如何在Redis中实现分页排序查询过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • SpringBoot整合Hutool实现文件上传的使用示例

    SpringBoot整合Hutool实现文件上传的使用示例

    文件上传在项目经常会用到,本文主要介绍了SpringBoot整合Hutool实现文件上传的使用示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • Java线程实现的两种方式解析

    Java线程实现的两种方式解析

    这篇文章主要介绍了Java线程实现的两种方式解析,注意在构造器中启动这个线程的话,很容易造成this逃逸的问题,这是要注意的,这是通过直接集成thread来成为线程,同时在这种情况下,你可以通过调用合适的方法来,需要的朋友可以参考下
    2024-01-01
  • IDEA使用properties配置文件进行mysql数据库连接的教程图解

    IDEA使用properties配置文件进行mysql数据库连接的教程图解

    Properties类是 键和值均为字符串的可以永久存储到文件中的key-value集合。这篇文章主要介绍了IDEA使用properties配置文件进行mysql数据路连接 ,需要的朋友可以参考下
    2018-10-10
  • SpringBoot实现单文件与多文件上传

    SpringBoot实现单文件与多文件上传

    本次例子不基于第三方存储(如七牛云对象存储、阿里云对象存储、腾讯云对象存储等),仅基于本地存储。本文主要内容如下:公共文件存储代码;单文件上传代码;多文件上传代码
    2021-05-05
  • Java GUI制作简单的管理系统

    Java GUI制作简单的管理系统

    这篇文章主要为大家详细介绍了Java GUI制作简单的管理系统的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • Spring Boot设置并使用缓存的步骤

    Spring Boot设置并使用缓存的步骤

    今天小编就为大家分享一篇关于Spring Boot设置并使用缓存的步骤,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java报错Non-terminating decimal expansion解决分析

    Java报错Non-terminating decimal expansion解决分析

    这篇文章主要为大家介绍了Java报错Non-terminating decimal expansion解决方案及原理分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • IDEA入门级使用教程你居然还在用eclipse?

    IDEA入门级使用教程你居然还在用eclipse?

    上个月,idea的使用量超越eclipse的消息席卷了整个IT界,idea到底好在哪里呢?下面小编通过本文给大家详细介绍下IDEA入门级使用教程,非常详细,感兴趣的朋友一起看看吧
    2020-10-10
  • 剑指Offer之Java算法习题精讲数组与列表的查找及字符串转换

    剑指Offer之Java算法习题精讲数组与列表的查找及字符串转换

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03

最新评论