ZooKeeper是分布式协调服务,不是一种静态框架或工具集,它是需要独立部署运行起来的中心化协调服务,分布式系统中的分布式进程通过调用ZooKeeper的服务来实现彼此的协调与约定,具体是通过ZooKeeper的客户端API来操作内存数据节点(ZNode)。
如图,ZooKeeper的数据模型为层次化命名空间树,树上每个节点称为数据节点(ZNode),这些ZNode可以被分布式进程客户端通过统一的API来调用操作,同时每个ZNode都是通过层次化命名路径来定位的,如上图中最下方的节点就可以通过路径“/app1/app3”来确定。
分布式进程通过操作ZNode来实现彼此的动作协调,但这种协调本身不是一直长时间持续发生的,比如多个分布式进程互斥访问共享资源,经过一段时间每个进程都访问成功,那么他们所操作的数据对象即ZNode现在是不是可以被回收掉,而没必要一直存在内存中占用资源?另外某些场景下协调的结果是需要长期保存下来,因为他们需要被频繁使用的,也可能在使用的过程中被更新,如分布式选举的结果,分布式配置管理等,此时的ZNode就需要一直存在内存中并且能够存储一定量的协调结果数据。
针对以上场景分析,ZooKeeper的ZNode引入了2种类型和Key-Value数据存储特性,如下图:
sequential_flag=Ture | sequential_flag=False | |
Regular(常规节点) | 客户端需要显示的创建和删除节点,如果没有显示的删除,节点会一直存在。节点名字末尾会被自动添加一个计数值作为最后创建的名字,而这个计数值在同一层级单调递增 | 创建节点的时候,不会在节点名字末尾添加任何内容 |
Ephemeral(临时节点) | 临时节点可以被客户端显示的创建和删除,也可以在会话结束后被系统自动删除。同时临时节点不能创建子节点。顺序特性如上。 | 创建节点的时候,不会在节点名字末尾添加任何内容 |
节点是数据对象,那么它包含哪些字段,在内存中是如何表示的呢?详细字段如下图所示:
ZNode在内存中是表示为DataNode的类,它本身包含的信息有父节点Parent,同样是一个ZNode;本身存储的数据Data,类型为二进制数组;访问权限ACL,是一个Long型的数据(之后会讲到),节点本身的状态信息Stat,表示了当前节点的所有状态数据;孩子列表Children,是一个String类型的集合。其中Stat表的信息字段具体解释如下:
状态属性 | 说明 |
czxid | 即Created ZXID,表示该数据节点创建时的事务ID |
mzxid | 即Modified ZXID,表示该节点最后一次被更新时的事务ID |
ctime | 即Created Time,表示节点被创建的时间 |
mtime | 即Modified Time,表示节点最后一次被更新的时间 |
version | 数据节点的当前版本 |
cversion | 子节点的版本号,表示子节点被修改次数 |
aversion | 节点的ACL的版本号 |
ephemeralOwner | 创建该临时节点的会话ID,如果是常规节点默认为0 |
dataLength | 数据内容长度 |
numChildren | 子节点的个数 |
pzxid | 子节点列表最后一次被修改时的事务ID,子节点内容变更不会影响此值 |
Stat数据示例如下:
[zk: zookeeper2(CONNECTED) 1] get /test20000000002
test
cZxid = 0x10000000a
ctime = Thu Nov 24 13:59:41 GMT 2016
mZxid = 0x10000000a
mtime = Thu Nov 24 13:59:41 GMT 2016
pZxid = 0x10000000a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: zookeeper2(CONNECTED) 2]
ZooKeeper的分布式协调服务是通过在内部实现一个高性能的协调内核以及开放一组API来让用户自行构建高级的分布式协调服务功能,而不需要开发很多特定语义的分布式协调服务功能。其中开放的API就是用来操作ZNode的,那么这些API都有哪些操作?如下所示:
create(path,data,flags):创建ZNode,路径名为path,存储数据data,flags是节点类型
delete(path,version):删除指定的路径path和版本version的ZNode
exists(path,watch):返回是否指定的path路径的节点存在,并且watch该路径
getData(path,watch):获取指定path路径的节点存储的数据,并且watch该路径
setData(path,data,version):存储指定数据data在指定路径path的指定版本节点上
getChildren(path,watch):返回指定path路径节点的所有孩子的名字集合
sync(path):等待所有挂起的更新操作都同步到当前连接的zookeeper服务器节点