zoukankan      html  css  js  c++  java
  • ZooKeeper的Znode剖析

    版权声明:本文为博主原创文章,转载请注明出处: http://blog.csdn.net/lihao21 或 leehao.me

    在ZooKeeper中,节点也称为znode。由于对于程序员来说,对zk的操作主要是对znode的操作,因此,有必要对znode进行深入的了解。 
    ZooKeeper采用了类似文件系统的的数据模型,其节点构成了一个具有层级关系的树状结构。例如,图1展示了zk节点的层级树状结构。

     

    图1中,根节点 / 包含了两个字节点 /module1,/module2,而节点 /module1 又包含了三个字节点 /module1/app1,/module1/app2,/module1/app3。在zk中,节点以绝对路径表示,不存在相对路径,且路径最后不能以 / 结尾(根节点除外)。

    类型

    根据节点的存活时间,可以对节点划分为持久节点和临时节点。节点的类型在创建时就被确定下来,并且不能改变。 
    持久节点的存活时间不依赖于客户端会话,只有客户端在显式执行删除节点操作时,节点才消失。 
    临时节点的存活时间依赖于客户端会话,当会话结束,临时节点将会被自动删除(当然也可以手动删除临时节点)。利用临时节点的这一特性,我们可以使用临时节点来进行集群管理,包括发现服务的上下线等。 
    ZooKeeper规定,临时节点不能拥有子节点。

    持久节点

    使用命令create可以创建一个持久节点。

    create /module1 module1

    这样,便创建了一个持久节点/module1,且其数据为”module1”。

    临时节点

    使用create命令,并加上-e参数,可以创建一个临时节点。

    create -e /module1/app1 app1

    这样,便创建了一个临时节点 /module1/app1,数据为”app1”。关闭会话,然后输入命令:

    get /module1/app1

    可以看到有以下提示,说明临时节点已经被删除。

    Node does not exist: /module1/app1

    顺序节点

    ZooKeeper中还提供了一种顺序节点的节点类型。每次创建顺序节点时,zk都会在路径后面自动添加上10位的数字(计数器),例如 < path >0000000001,< path >0000000002,……这个计数器可以保证在同一个父节点下是唯一的。在zk内部使用了4个字节的有符号整形来表示这个计数器,也就是说当计数器的大小超过2147483647时,将会发生溢出。 
    顺序节点为节点的一种特性,也就是,持久节点和临时节点都可以设置为顺序节点。这样一来,znode一共有4种类型:持久的、临时的,持久顺序的,临时顺序的。

    使用命令create加上-s参数,可以创建顺序节点,例如,

    create -s /module1/app app

    输出:

    Created /module1/app0000000001

    便创建了一个持久顺序节点 /module1/app0000000001。如果再执行此命令,则会生成节点 /module1/app0000000002。 
    如果在create -s再添加-e参数,则可以创建一个临时顺序节点。

    节点的数据

    在创建节点时,可以指定节点中存储的数据。ZooKeeper保证读和写都是原子操作,且每次读写操作都是对数据的完整读取或完整写入,并不提供对数据进行部分读取或者写入的操作。 
    以下命令创建一个节点/module1/app2,且其存储的数据为app2。

    create /module1/app2 app2

    ZooKeeper虽然提供了在节点存储数据的功能,但它并不将自己定位为一个通用的数据库,也就是说,你不应该在节点存储过多的数据。Zk规定节点的数据大小不能超过1M,但实际上我们在znode的数据量应该尽可能小,因为数据过大会导致zk的性能明显下降。如果确实需要存储大量的数据,一般解决方法是在另外的分布式数据库(例如redis)中保存这部分数据,然后在znode中我们只保留这个数据库中保存位置的索引即可。

    节点的属性

    每个znode都包含了一系列的属性,通过命令get,我们可以获得节点的属性。

    get /module1/app2 
    app2 
    cZxid = 0x20000000e 
    ctime = Thu Jun 30 20:41:55 HKT 2016 
    mZxid = 0x20000000e 
    mtime = Thu Jun 30 20:41:55 HKT 2016 
    pZxid = 0x20000000e 
    cversion = 0 
    dataVersion = 0 
    aclVersion = 0 
    ephemeralOwner = 0x0 
    dataLength = 4 
    numChildren = 0

    版本号

    对于每个znode来说,均存在三个版本号:

    • dataVersion 
      数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据)。
    • cversion 
      子节点的版本号。当znode的子节点有变化时,cversion 的值就会增加1。
    • aclVersion 
      ACL的版本号,关于znode的ACL(Access Control List,访问控制),可以参考 参考资料1 有关ACL的描述。

    以数据版本号来说明zk中版本号的作用。每一个znode都有一个数据版本号,它随着每次数据变化而自增。ZooKeeper提供的一些API例如setData和delete根据版本号有条件地执行。多个客户端对同一个znode进行操作时,版本号的使用就会显得尤为重要。例如,假设客户端C1对znode /config写入一些配置信息,如果另一个客户端C2同时更新了这个znode,此时C1的版本号已经过期,C1调用setData一定不会成功。这正是版本机制有效避免了数据更新时出现的先后顺序问题。在这个例子中,C1在写入数据时使用的版本号无法匹配,使得操作失败。图2描述了这个情况。

     

    图2:使用版本号来阻止并行操作的不一致性

    事务ID

    对于zk来说,每次的变化都会产生一个唯一的事务id,zxid(ZooKeeper Transaction Id)。通过zxid,可以确定更新操作的先后顺序。例如,如果zxid1小于zxid2,说明zxid1操作先于zxid2发生。 
    需要指出的是,zxid对于整个zk都是唯一的,即使操作的是不同的znode。

      • cZxid 
        Znode创建的事务id。

      • mZxid 
        Znode被修改的事务id,即每次对znode的修改都会更新mZxid。

    图3:Zxid在客户端重连中的作用

    在集群模式下,客户端有多个服务器可以连接,当尝试连接到一个不同的服务器时,这个服务器的状态要与最后连接的服务器的状态要保持一致。Zk正是使用zxid来标识这个状态,图3描述了客户端在重连情况下zxid的作用。当客户端因超时与S1断开连接后,客户端开始尝试连接S2,但S2延迟于客户端所识别的状态。然而,S3的状态与客户端所识别的状态一致,所以客户端可以安全连接上S3。

    时间戳

    包括znode的创建时间和修改时间,创建时间是znode创建时的时间,创建后就不会改变;修改时间在每次更新znode时都会发生变化。

    以下命令创建了一个 /module2 节点。

    create /module2 module2 
    Created /module2

    通过 get 命令,可以看到 /module2的 ctime和mtime均为Sat Jul 02 11:18:32 CST 2016。

    get /module2 
    module2 
    cZxid = 0x2 
    ctime = Sat Jul 02 11:18:32 CST 2016 
    mZxid = 0x2 
    mtime = Sat Jul 02 11:18:32 CST 2016 
    pZxid = 0x2 
    cversion = 0 
    dataVersion = 0 
    aclVersion = 0 
    ephemeralOwner = 0x0 
    dataLength = 7 
    numChildren = 0

    修改 /module2,可以看到 ctime 没有发生变化,mtime已更新为最新的时间。

    set /module2 module2_1 
    cZxid = 0x2 
    ctime = Sat Jul 02 11:18:32 CST 2016 
    mZxid = 0x3 
    mtime = Sat Jul 02 11:18:50 CST 2016 
    pZxid = 0x2 
    cversion = 0 
    dataVersion = 1 
    aclVersion = 0 
    ephemeralOwner = 0x0 
    dataLength = 9 
    numChildren = 0

    参考资料

      1. http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkDataModel
      2. http://java.globinch.com/enterprise-services/zookeeper/apache-zookeeper-explained-tutorial-cases-zookeeper-java-api-examples/#
      3. 《ZooKeeper分布式过程协同技术详解》,Flavio Junqueira等著,谢超等译
  • 相关阅读:
    LintCode Python 简单级题目 488.快乐数
    LintCode Python 简单级题目 100.删除排序数组中的重复数字 101.删除排序数组中的重复数字II
    LintCode Python 简单级题目 373.奇偶分割数组
    LintCode Python 简单级题目 39.恢复旋转排序数组
    LintCode Python 简单级题目 35.翻转链表
    LintCode Python 简单级题目 451.两两交换链表中的节点
    LintCode Python 简单级题目 174.删除链表中倒数第n个节点
    aws查看官方centos镜像imageid
    linux shell脚本查找重复行/查找非重复行/去除重复行/重复行统计
    php配置优化-生产环境应用版
  • 原文地址:https://www.cnblogs.com/aoshicangqiong/p/7900656.html
Copyright © 2011-2022 走看看