专栏首页龙首琴剑庐Zookeeper 数据结构详解

Zookeeper 数据结构详解

Zookeeper

https://zookeeper.apache.org/doc/current/zookeeperOver.html

ZooKeeper is a distributed, open-source coordination service for distributed applications.
It exposes a simple set of primitives that distributed applications can build upon to implement higher level services for synchronization, configuration maintenance, and groups and naming.

It is designed to be easy to program to, and uses a data model styled after the familiar directory tree structure of file systems. 

Zookeeper是高性能,高可用,严格有序的分布式协调服务,提供了统一配置(configuration),命名(naming),同步(synchronization),以及分组服务(group service)。

同时,Zookeeper本身支持复制集群,实例间是两两连接的,维护内存中的数据状态,并持久存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper服务将可用。 在“读为主”的工作负载中,它特别快。ZooKeeper应用程序可在数千台计算机上运行,并且在读取比写入更为常见的情况下,其性能最佳,比率约为10:1。

Zookeeper 保证的特性

  • 顺序一致性(Sequential Consistency):来自客户端的更新将按照其发送顺序进行执行。
  • 原子性(Atomicity):更新成功或失败。没有中间状态的结果。
  • 统一视图(Single System Image):无论客户端连接到哪个服务器,客户端都将看到相同服务的数据视图。
  • 可靠性(Reliability): 一旦数据更新被执行了,它将从那时起持续到客户端覆盖更新。
  • 及时性(Timeliness):确保系统的客户视图在特定时间范围内是最新的。

Zookeeper的数据结构

ZooKeeper提供的名称空间与标准文件系统的名称空间非常相似。

名称是由斜杠(/)分隔的一系列路径元素。ZooKeeper命名空间中的每个节点都由路径进行唯一标识。

ZooKeeper的层次命名空间

与标准文件系统不同,ZooKeeper命名空间中的每个节点都可以具有与其关联的数据以及子节点。就像拥有一个文件系统一样,该文件系统也允许文件成为目录。 每一个节点都可以存储数据,只是需要注意的是存储的容量是有限,一般不能超过 1MiB。

Znode 类型
  • Znode的类型分为三类:
    • 持久节点(persistent node)节点会被持久
    • 临时节点(ephemeral node),客户端断开连接后,ZooKeeper会自动删除临时节点
    • 顺序节点(sequential node),每次创建顺序节点时,ZooKeeper都会在路径后面自动添加上10位的数字,从1开始,最大是2147483647 (2^32-1) 每个顺序节点都有一个单独的计数器,并且单调递增的,由Zookeeper的leader实例维护。
  • Znode实际上有四种形式,默认是persistent
    • PERSISTENT 持久节点: 如 create /test/a "hello" ,通过 create <path> <data>参数指定为持久节点
    • PERSISTENT_SEQUENTIAL(持久顺序节点/s0000000001) ,通过 create -s <path> <data>参数指定为顺序节点
    • EPHEMERAL 临时节点,通过 create -e <path> <data>参数指定为顺序节点
    • EPHEMERAL_SEQUENTIAL(临时顺序节点/s0000000001) ,通过 create -s -e <path> <data> 参数指定为临时及顺序节点
  • 下面是一些实例:

(1) 创建顺序节点

[zk: 127.0.0.1:2281(CONNECTED) 0] create /seq_test/ ""
Created /seq_test
[zk: 127.0.0.1:2281(CONNECTED) 1] create -s /seq_test/s "hello"
Created /seq_test/s0000000001
[zk: 127.0.0.1:2281(CONNECTED) 2] create -s /seq_test/s "hello"
Created /seq_test/s0000000002
[zk: 127.0.0.1:2281(CONNECTED) 3] ls /seq_test
[s0000000001, s0000000002]

(2) 创建临时节点

[zk: 127.0.0.1:2281(CONNECTED) 0] create /ephe_test/ ""
Created /ephe_test
[zk: 127.0.0.1:2281(CONNECTED) 1] create -e /ephe_test/e "hello"
Created /ephe_test/e
[zk: 127.0.0.1:2281(CONNECTED) 2] ls /ephe_test
[e]

断开重新连接

[zk: 127.0.0.1:2281(CONNECTED) 0] ls /ephe_test
[]

(3) 创建临时顺序节点

[zk: 127.0.0.1:2281(CONNECTED) 0] create /ephe_seq_test/ ""
Created /ephe_seq_test
[zk: 127.0.0.1:2281(CONNECTED) 1] create -e -s /ephe_seq_test/s "hello"
Created /ephe_seq_test/s0000000001
[zk: 127.0.0.1:2281(CONNECTED) 2] ls /ephe_seq_test
[s0000000001]
Zxid(ZooKeeper Transaction Id

每次的变化都会产生一个集群全局的唯一的事务id, Zxid(ZooKeeper Transaction Id),由Zookeeper的leader实例维护。 这里的变化包括:

  • 任何的客户端连接到Server
  • 任何的客户端断开与Server连接
  • 任何的Znode节点被创建create、修改set、删除deletermr

Zxid是一个64位的数字,高32位表示纪元,从1开始,每次选举出一个新的leader,就会递增1;低32位是当前纪元维护的单调递增的数字,同样从1开始。

Znode 属性
  • cZxid :创建的事务标识。
  • ctime:创建的时间戳
  • mZxid:修改的事务标识,每次修改操作(set)后都会更新mZxidmtime
  • mtime:修改的时间戳
  • pZxid:直接子节点最后更新的事务标识,子节点有变化(创建create、修改set、删除deletermr)时,都会更新pZxid
  • cversion :直接子节点的版本号。当子节点有变化(创建create、修改set、删除deletermr)时,cversion 的值就会增加1。
  • dataVersion :节点数据的版本号,每次对节点进行修改操作(set)后,dataVersion的值都会增加1(即使设置的是相同的数据)。
  • aclVersion :节点ACL的版本号,每次节点的ACL进行变化时,aclVersion 的值就会增加1。
  • ephemeralOwner:当前节点是临时节点(ephemeral node )时,这个ephemeralOwner的值是客户端持有的session id。
  • dataLength:节点存储的数据长度,单位为 B (字节)。
  • numChildren:直接子节点的个数。
➜ zkCli.sh -server 127.0.0.1:2281
[zk: 127.0.0.1:2281(CONNECTED) 0] get /

cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

默认根节点 / 和 /zookeeper 是存在,因此 cZxid 是 0x0。

[zk: 127.0.0.1:2281(CONNECTED) 1] ls /
[zookeeper]
[zk: 127.0.0.1:2281(CONNECTED) 2] create /test "hello"
Created /test
[zk: 127.0.0.1:2281(CONNECTED) 3] ls /
[zookeeper, test]

当创建了一个 /test 节点后,根节点的子节点就多出来了。

[zk: 127.0.0.1:2281(CONNECTED) 4] get /test
hello
cZxid = 0x100000002
ctime = Sat May 23 15:43:10 CST 2020
mZxid = 0x100000002
mtime = Sat May 23 15:43:10 CST 2020
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

为什么cZxid 高32位是 0x1 表明了当前纪元为第一代,低32位是00000002 表明了当前纪元第2笔事务操作创建了 /test 节点。 为什么是2呢?因为我们是通过 zkCli.sh 客户端连接到Server的,这里会消耗一次 Zxid。

[zk: 127.0.0.1:2281(CONNECTED) 5] set /test "hello world"
cZxid = 0x100000002
ctime = Sat May 23 15:43:10 CST 2020
mZxid = 0x100000003
mtime = Sat May 23 15:43:41 CST 2020
pZxid = 0x100000002
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 11
numChildren = 0

修改 /test 节点数据,mZxidmtimedataVersion发生了变化, dataLength 变为了( "hello world"占用了11个字节)。

[zk: 127.0.0.1:2281(CONNECTED) 6] create /test/a ""   
Created /test/a
[zk: 127.0.0.1:2281(CONNECTED) 7] get /test              
hello world
cZxid = 0x100000002
ctime = Sat May 23 15:43:10 CST 2020
mZxid = 0x100000003
mtime = Sat May 23 15:43:41 CST 2020
pZxid = 0x100000004
cversion = 1
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 11
numChildren = 1

创建 子节点 /test/a,我们查看 /test 节点属性,发现 pZxidcversion, numChildren 都发生了变化。

[zk: 127.0.0.1:2281(CONNECTED) 8] get /test/a

cZxid = 0x100000004
ctime = Sat May 23 15:44:12 CST 2020
mZxid = 0x100000004
mtime = Sat May 23 15:44:12 CST 2020
pZxid = 0x100000004
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0

查看 /test/a 节点属性,发现 cZxid 与 父节点的 pZxid 是一致的,证实了 pZxid是直接子节点最后更新的事务标识。

Znode的监视(Watch)

ZooKeeper支持 Watch。客户端可以在znode上设置 Watch。

znode更改时,将触发并删除监视。触发监视后,客户端会收到一个数据包,说明znode已更改。

如果客户端与其中一个ZooKeeper服务器之间的连接断开,则客户端将收到本地通知。

3.6.0中的新增功能:

客户端还可以在znode上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发注册znode以及所有子znode的更改。

支持 Watch的 客户端命令:

  • stat path [watch]
  • ls path [watch]
  • ls2 path [watch]
  • get path [watch]
[zk: 127.0.0.1:2281(CONNECTED) 3] get /test/d watch

cZxid = 0x100000013
ctime = Sat May 23 16:47:41 CST 2020
mZxid = 0x100000013
mtime = Sat May 23 16:47:41 CST 2020
pZxid = 0x100000013
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0

此时使用另外一个客户端去更改 /test/d 节点的数据,我们就可以看到原来的客户端自动收到了一个WATCHER 通知。

[zk: 127.0.0.1:2281(CONNECTED) 4] 
WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/test/d
 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CPU体系结构

    在微指令架构的 CPU 里面,编译器编译出来的机器码和汇编代码并没有发生什么变化。但在指令译码的阶段,指令译码器“翻译”出来的,不再是某一条 CPU 指令。译...

    斯武丶风晴
  • Redis 集群演进探讨和总结

    Redis单点故障,可以通过主从复制replication,和自动故障转移sentinel哨兵机制。

    斯武丶风晴
  • Java可变参数列表

    1、接受的传入参数情况 如public void test(String ...args){...}  1)不使用参数,如test() 2)使用一个或多个参数,...

    斯武丶风晴
  • 关于移动用户体验设计的那些事,你知道吗?

    以下内容由摹客团队翻译整理,仅供学习交流,摹客是设计+协作一站式云平台,从产品、设计到开发,摹客来解决。

    奔跑的小鹿
  • Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET、PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器。最新版 5.8...

    张善友
  • 火狐和谷歌浏览器对js事件兼容问题

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <titl...

    botkenni
  • 为世界构建应用程序

    在155个国家和40多种语言中增长您的业务, 并帮助世界各地的用户轻松地发现和下载您的应用程序。

    iOSDevLog
  • Django源码学习-6-App 应用程序注册

    Django网络应用开发的5项基础核心技术包括模型(Model)的设计,URL 的设计与配置,View(视图)的编写,Template(模板)的设计和Form(...

    小团子
  • Jquery find与filter函数区别

    find()会在div元素内 寻找 class为classname的元素。 filter()则是筛选div的class为classname的元素。 基本是...

    wangxl
  • iptables之NAT端口转发设置

    背景: 服务器A:103.110.114.8/192.168.1.8,有外网ip,是IDC的一台服务器 服务器B:192.168.1.150,没有外网ip,A服...

    洗尽了浮华

扫码关注云+社区

领取腾讯云代金券