zoukankan      html  css  js  c++  java
  • zookeeper分布式锁

    Zookeeper 架构

    首先简单介绍下 Zookeeper 集群,一个 Zookeeper 集群通常由一组机器组成,一般3~5台集群就可以组成一个 Zookeeper 集群。集群拓扑图基本如下:

     

     

    Zookeeper 集群中每一个节点都会在内存中维护当前的节点状态,并且彼此之间保持着通信

    Leader

    Leader 节点整个 Zookeeper 集群工作机制中的核心,主要工作是处理客户端的读写请求,及集群内部各服务的调度。注意只有 leader 能够处理写请求。

    Follower

    处理客户端的读请求;如果有写请求,则将写请求转发给 leader;参与 leader 选举投票等。

    Zookeeper 数据模型

    Zookeeper 的数据模型是一棵类似 Unix 文件系统的 ZNode Tree 即 ZNode 树,术语叫做 ZNode。ZNode 是 Zookeeper 存储数据的最小单元,每个 ZNode 可以保存数据,也可以挂载子节点,其中根节点是 /。示意图如下:

     

    Zookeeper 主要提供了两个核心功能:

    • 管理(存储、读取)客户端提交的数据;

    • 为客户端提供ZNode的监听服务;

    这里就涉及到 Zookeeper 的两个重要特性,就是它的 ZNode 模型Watcher 机制

    ZNode 模型

    znode节点有4种类型:持久节点,临时节点,持久有序节点,临时有序节点

    • 持久节点(PERSISTENT):客户端与 Zookeeper 断开会话后,该节点依旧存在,直到执行删除操作才会删除节点。

    • 持久顺序节点(PERSISTENT_SEQUENTIAL):另一种持久节点,不同的是zookeeper会给该节点名称加上一个唯一单调递增的整数,也就是持久有序节点

    • 临时节点(EPHEMERAL):节点的生命周期和客户端的会话绑定在一起,如果客户端崩溃了或者关闭了与 ZooKeeper的连接,这个节点就会被自动删除

    • 临时顺序节点(EPHEMERAL_SEQUENTIAL):概念和上面类似,Zookeeper 也会给该节点进行顺序编号。

    ZNode 除了存储用户数据外,还有以下特点:

    • 包含 ZNode 修改/访问的时间、事务id(zxid),ACL 权限、版本等状态信息;

    • 所有的事务请求在 ZNode 端都是顺序和原子性的;

    • 数据主要存储在内存中,磁盘中保存事务日志、快照数据等;

    Watcher 机制

    Watcher 机制也称监听机制,它是 Zookeeper 的关键特性,是通过 ZooKeeper 实现分布式发布/订阅、分布式锁、集群管理等功能的基础。

    ZooKeeper 客户端获得服务器的数据或者变化,不是通过轮询的模式,而是基于通知的机制,客户端向 ZooKeeper 服务器端注册需要监听的znode,如果被监听的znode发生了改变(比如节点被删除,节点数据发变更),则会通知客户端,需要强调的是这一个单次触发的操作。

     

    代码演示 Zookeeper 监听器

    首先,当前有一个包含3个节点的 Zookeeper 集群,我们根据 Zookeeper 版本引入了相应依赖,如下

    演示代码

    • 创建 ZNode

     

    执行完这个单元测试后,我们通过命令行在服务端查看一下该数据节点:



    • 删除 ZNode 节点,并监听该节点的删除动作

     

    代码执行后,可以看到控制台打印出了znode被删除的日志:

    再去服务端查看该节点,可以看到已经不存在了:

     

    Zookeeper分布式锁的原理

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

    获取锁

    首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端Client1想要获得锁时,需要在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

    释放锁

    释放锁分为两种情况:

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

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

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

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

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

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

     

    参考:

    ZooKeeper 源码和实践揭秘

    如何用Zookeeper实现分布式锁

    一文了解 Zookeeper 基本原理与应用场景

  • 相关阅读:
    [Codeforces 339D] Xenia and Bit Operations
    [Codeforces 459D] Pashmak and Parmida's problem
    [Codeforces 460C] Present
    [Codeforces 466C] Number of Ways
    [Codeforces 650A] Watchmen
    Linux系统中‘dmesg’命令处理故障和收集系统信息的7种用法
    select函数详解
    都是stm32的JTAG引脚惹的祸
    uboot中的快捷菜单的制作说明
    卷积的本质及物理意义(全面理解卷积)
  • 原文地址:https://www.cnblogs.com/zz-ksw/p/12822307.html
Copyright © 2011-2022 走看看