zoukankan      html  css  js  c++  java
  • Zookeeper是如何实现分布式锁的

    Zookeeper是如何实现分布式锁的

    标签 : Zookeeper 分布式


    实现分布式锁要考虑的重要问题

    1. 三个核心要素

    加锁, 解锁, 锁超时

    2. 三个问题

    • 要保证原子性操作, 加锁和锁超时的操作要一次性执行完毕
    • 防止误删锁
    • 在误删的基础上, 加一个守护线程, 为锁续命.

    什么是临时顺序节点


    Zookeeper的数据存储结构就像是一棵树, 这棵树由节点组成, 这种节点叫做Znode. Znode分为四种类型.

    1. 持久节点(Persistent)

    默认的节点类型, 创建节点的客户端和Zookeeper断开连接之后, 该节点依旧存在.

    2. 持久顺序节点(Persistent Sequential)

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

    顺序持久节点

    3. 临时节点(Ephemeral)

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

    创建临时节点
    断开客户端
    删除临时节点

    4. 临时顺序节点(Ephemeral Sequential)

    在创建节点时, Zookeeper根据创建的时间顺序给该节点名称进行编号; 当创建节点的客户端与Zookeeper断开连接之后,临时节点会被删除.


    Zookeeper实现分布式锁的原理

    上面已经说了Znode的四种类型, 其中最后一种类型 临时顺序节点 是最有利于实现Zookeeper分布式锁的.


    1. 获取锁

    • 首先, 在Zookeeper当中创建一个持久节点ParentLock. 当第一个客户端想要获得操作某项数据的锁的时候,需要在该持久节点之下简历一个临时顺序节点Lock1.

    客户端1尝试获得所

    • 之后, 客户端1 查找ParentLock下面所有的临时顺序节点并按照大小排序, 判断自己所创建的节点Lock1是不是顺序最靠前的一个. 如果是第一个节点,则成功获得锁.

    客户端1成功获得所

    • 此时, 客户端2 前来获取该项数据的锁, 则在ParentLock下再创建一个临时顺序节点Lock2.

    客户端2尝试获得锁

    • 客户端2 查找ParentLock下面所有的临时顺序节点并排序,发现自己的Lock2节点并不是最靠前的. 于是客户端2向排序仅仅比它靠前的Lock1注册Watcher, 用于监听Lock1动态. 这意味着 Lock2抢锁失败, 进入等待状态.

    Lock2抢锁失败

    • 此时, 如果有一个客户端3前来获取锁, 则在ParentLock下在创建一个临时顺序节点Lock3.

    Lock3尝试获得锁

    • 客户端3查找ParentLock下面所有的临时顺序节点并排序, 判断自己所创建的节点Lock3是不是顺序最靠前的一个, 结果发现Lock3不是最靠前的. 于是客户端3同样抢锁失败, 进入了等待状态.

    Lock抢锁失败

    • 这个时候客户端1得到了锁, 客户端2监听了客户端1, 客户端3监听了客户端2. 这样刚好形成一个等待的队列.

    2. 释放锁

    释放锁有两种情况

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

    • 当任务完成时, 客户端1会显示的调用删除节点Lock1的指令.

    客户端1释放锁

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

    • 获得锁的客户端1在执行任务的过程中, 如果崩溃, 则会断开和Zookeeper服务器的链接, 根据临时节点的特性, 相关联的Lock1会随之自动删除.

    客户端1崩溃,自动释放锁

    3. 获得锁

    • 由于客户端2一直在监听Lock1的状态,这个时候发现Lock1注销了, 客户端2会立即接收到通知. 这个时候客户端2会再次查询ParentLock下的所有节点, 确认自己所创建的节点是不是最小的节点, 如果是最小的则成功获得锁.

    客户端2成功获得锁

    同理可推至客户端3


    总结

    Zookeeper和Redis分布式锁的比较

    分布式锁 优点 缺点
    Zookeeper 1.有封装好的框架,容易实现.
    2.有等待锁的机制(Watcher),可以提高抢锁的效率,好处多多
    添加和删除节点的性能比较低
    Redis SetDel的性能比较高(毕竟键值数据库,Hash) 1.实现复杂,需要考虑原子性,误删等情况.
    2.没有等待锁的机制,只能通过客户端的自旋来等锁,效率低下.

    9: https://www.funtl.com/assets/Lusifer2018101900098]: https://www.funtl.com/assets/Lusifer201810190008.png

  • 相关阅读:
    【JavaScript DOM 编程艺术】 笔记
    如何循序渐进有效学习 JavaScript?
    如何正确学习JavaScript
    HTML5学习
    window上杀死node进程
    HTML5:离线存储
    js面向对象的理解
    H5项目常见问题及注意事项
    查找已连接过的wifi密码
    flex的兼容
  • 原文地址:https://www.cnblogs.com/A-FM/p/11440656.html
Copyright © 2011-2022 走看看