Zookeeper学习笔记——Zookeeper系统模型

从数据模型、节点特性、版本、Watcher和ACL五方面分析Zookeeper的系统模型。
1、数据模型
如图1所示,Zookeeper的数据模型在结构上与Unix文件系统类似,采用树型层次结构,Zookeeper树中每个节点称为Znode。
Zookeeper学习笔记——Zookeeper系统模型_第1张图片
图1 Zookeeper数据模型

在Zookeeper中,事务是指能够改变Zookeeper服务器状态的操作,包括数据节点创建/删除、数据节点内容更新以及客户端会话创建/失效等。对于每个事务请求,Zookeeper都会分配一个全局唯一的事务ID,用ZXID表示,通常是一个64位的数字,高32位是epoch用来标识leader关系是否改变,每次新leader被选出,都会有一个新的epoch。低32位是个递增计数。
2、节点特性
引用方式:Znode通过绝对路径引用,并且路径唯一标识,如:Server1这个znode的标识为/NameService/Server1。
节点类型:临时节点(EHPEMERAL)和永久节点(PERSISTENT)。节点的类型在创建的时候确定,不能改变。
1)临时节点:临时节点的生命周期和客户端会话绑定在一起,即:如果Session失效(非客户端连接断开),则临时节点会被自动删除。Zookeeper规定临时节点不允许拥有子节点,只能是叶子节点。
2)永久节点:永久节点生命周期不依赖于会话,必须由客户端主动删除才行。
节点的顺序性(SEQUENTIAL):创建Znode时,可在路径结尾添加“递增计数”,此计数对于父节点唯一,格式为:“%10d”(10位数字,没有数值的数位用0补充,比如:0000000001)。
状态信息:Znode除了存储数据内容外,还存储了节点本身的一些状态信息(Stat结构),使用get命令获取节点内容,如图2所示。
Zookeeper学习笔记——Zookeeper系统模型_第2张图片
图2 get命令获取节点信息
如图2所示,第一行是节点的数据内容,从第二行开始就是节点的状态信息。Zookeeper中Stat结构描述了节点的所有状态信息,包括:事务ID、版本信息和子节点个数等,如表6.1所示。
表1 Zookeeper的Stat结构说明
Zookeeper学习笔记——Zookeeper系统模型_第3张图片

3、版本——保证分布式数据原子性操作
Znode有三种类型的版本信息,每个对数据节点的任何更新操作都会引起版本号的变化:
version:节点数据内容版本号;
cversion:节点中子节点的版本号;
aversion:节点的ACL版本号
Znode的版本信息主要用于数据校验。在并发流程中,可以通过版本号检查数据读取之后、写入之前有没有被修改过。

4、Watcher——事件变化通知
Zookeeper允许客户端向服务器注册Watcher监听,当服务端的一些指定事件触发了这个Watcher,就会想指定客户端发送一个事件通知来实现分布式的通知功能。Watcher注册与通知过程如图3所示。
Zookeeper学习笔记——Zookeeper系统模型_第4张图片
图3 Watcher注册与通知过程
如图3所示,Zookeeper的Watcher机制包括客户端线程、客户端Watcher管理和Zookeeper服务器三部分。工作流程:客户端在向Zookeeper服务器注册Watcher的同时,将Watcher存储在客户端的Watcher管理模块中,当Zookeepker服务端触发Watcher事件后,会想客户端发送通知,客户端线程从Watcher管理模块中取出对应的Watcher回调进行执行。
4.1、Watcher特性
Zookeeper客户端在节点上设置Watcher,当节点发生变化时,客户端会受到Watcher事件。Zookeeper中的各种读请求,比如getData()、getChildren()和exists(),都可以设置Watcher。Zookeeper的Watcher具有以下几个特性:
一次性:Watcher是一次性的,一旦触发就会被移除,需要客户端反复注册;
客户端串行执行:客户端Watcher的回调过程是一个串行的同步过程,不能因为一个Watcher的处理影响整个客户端的Watcher回调;
轻量:Watcher事件通知时,服务端仅需要告诉客户端(连接状态、事件类型、节点路径)发生了什么事情,而不需要说明事件的具体内容。
如果客户端A修改了节点的数据,那么Zookeeper不能保证Watcher事件会在修改数据的函数返回前到达客户端A;
Watcher保留在Zookeeper的服务端,当客户端连接到新的Zookeeper服务端时,所有相关Watcher都会被触发;当客户端断线后重连,与它相关的Watcher都会自动重新注册,所以,在特殊场景下Watcher可能会被错过,比如:客户端B设置了节点A存在性的Watcher,在B断线过程中节点A被创建又被删除,那么,B重连后并不知道A节点曾经被创建过。
Zookeeper的Watcher机制保证以下几点:
① Watcher事件的触发顺序与事件的分发顺序一致;
② 客户端先收到Watch事件,然后才会收到新的数据;
③ Watch事件触发的顺序与Zookeeper服务器上数据变化的顺序一致;

4.2、Watcher回调
Zookeeper定义了C库的Watcher回调函数,原型如下:

Typedef void (*watcher_fn)(zhandle_t *zh, int type, int state, const char *path, void *watcherCtx);

Watcher回调函数的参数主要包括:事件类型(type)、连接状态(state)和节点路径(path)。
客户端无法从事件中获取对应节点的数据内容,而是需要客户端再次主动去重新获取数据内容。
4.3、Watcher事件
Watcher处理事件分为两类:
连接状态事件(type=None,path=null):不需要注册、触发,只需处理;
节点事件:节点的创建、删除、数据修改,需要注册触发,并且可能出现事件丢失的情况。
同一个事件在不同的连接状态中代表的含义是不同的,表3列举了常见的连接状态和事件类型。
表3 连接状态和事件类型
Zookeeper学习笔记——Zookeeper系统模型_第5张图片

NodeDataChanged事件:此处指的是变更节点的数据内容和数据的版本号,即使使用相同的数据内容来更新,也会触发事件通知。对Zookeeper来说,无论内容更新与否,一旦客户端调用了数据更新接口,且更新成功,则数据版本号就会自动更新。
4.4、Watcher类型
Zookeeper客户端可以通过exists()、getChildren()和getData()设置Watcher,在Watcher监听的节点状态发生改变时,Watcher事件被异步发送给客户端。
Zookeeper中Watcher类型可以分为两种:
数据Watcher:Znode的数据内容发生变化时,会触发数据Watcher;
孩子Watcher:Znode的子节点发生变化(创建/删除)时,会触发孩子Watcher;
4.5、Watcher的触发
Zookeeper中Watcher的设置和触发条件如表4所示。
表4 Watcher的设置和触发条件
Zookeeper学习笔记——Zookeeper系统模型_第6张图片
注:NodeDelete表示Znode被删除,NodeDeleteChanged表示子节点被删除。
5、ACL(Access Control List)——保证数据安全
5.1、ACL介绍
Zookeeper的ACL权限控制的实现与Unix文件访问权限类似:使用许可位对Znode的不同操作进行允许或禁止的权限控制。与标准的Unix许可不同,Zookeeper对于用户类别的区分,不止局限于创建者(User)、创建者所在组(Group)和其他用户(Other)三个级别,而是使用ACL针对任意用户和组进行细粒度的权限控制。
Zookeeper使用“scheme?permission”来标识一个有效的ACL信息:
权限模式(Scheme):确定权限验证过程中使用的校验策略;
授权对象(ID):权限赋予的用户或指定实体,比如:IP地址或机器等;
权限(Permission):通过权限检查后可以被允许执行的操作。
(1)权限模式(Scheme)
Zookeeper中常用的几种权限模式:
① Digest:最常用的权限控制模式,客户端通过类似于“user:pwd”形式的权限标识进行权限控制。客户端通过“username:password”形式配置权限标识后,Zookeeper会对其先后进行两次编码处理,分别是SHA-1算法加密和BASE64编码。
② Ip:通过IP地址进行权限控制,比如:“ip:192.168.1.110”标识针对这个IP进行权限控制;同时,IP模式可以扩展为按照网段的方式进行配置,比如:“ip:192.168.0.1/24”标识针对192.168.0.*网段进行权限控制。
③ World:一种最开放的权限控制模式,节点的访问权限对所有用户开放,即所有的用户都可以不进行权限校验直接对节点操作,World模式只有一个权限标识:“world:anyone”。
④ Super:一种特殊的Digest模式,超级用户可以对任意Zookeeper上的节点进行任何操作。
(2)授权对象(ID)
不同的权限模式,授权对象也是不同的,如表2所示。
表2 权限模式和授权对象的对于关系
Zookeeper学习笔记——Zookeeper系统模型_第7张图片
(3)权限(Permission)
Zookeeper中,所有对数据的操作权限分为五类:
① CREATE(C):创建权限,允许授权对象在节点下创建子节点;
② DELETE(D):子节点删除权限,允许授权对象删除节点下的子节点;
③ Read(R):读权限,允许授权对象访问节点并读取其数据内容或子节点列表;
④ Write(W):写权限,允许授权对象对节点的数据内容进行更新;
⑤ Admin(A):管理权限,允许授权对象设置节点的ACL;
Zookeeper C API支持三种标准的用户权限,它们分别是:
① ZOO_OPEN_ACL_UNSAFE:任何应用程序可以在节点上执行任何操作;
② ZOO_READ_ACL_UNSAFE:所有应用程序都仅具有读权限;
③ ZOO_CREATOR_ALL_ACL:节点创建者具有所有权限。注意:设置此权限之前,创建者必须已经通过服务器认证。
5.2、ACL管理
(1)ACL格式
Znode的 ACL权限用整型数字perms表示,perms的5个二进制位分别表示setacl、delete、create、write、read。比如:adcwr=0x1f,----r=0x1,a-c-r=0x15。
注意:exists操作和getAcl操作并不受ACL许可控制,因此,任何客户端都可以查询节点的状态和ACL。
(2)设置ACL
通过zkCli脚本登录Zookeeper服务器后,可以通过两种方式设置ACL:
节点创建时同时设置ACL权限,命令格式:create [-s] [-e] path data acl
使用setAcl命令对已存在的节点设置ACL,命令格式:setAcl path acl
(3)ACL验证
客户端对Znode进行操作的ACL验证方式为:

  1. 遍历znode的ACL:
    ① 首先进行操作类型和权限(perms)匹配;
    ② 权限匹配成功后才会进行session的auth信息与ACL的用户名、密码匹配
  2. 两次匹配成功,则允许操作;否则返回权限不够(rc=-102)。

你可能感兴趣的:(Zookeeper)