来自《Hadoop实战》陆嘉恒

1、ZooKeeper的数据模型

ZooKeeper拥有一个层次的命名空间,这和分布式的文件系统非常相似。唯一不同的地方是命名空间中的每个节点可以有和它自身或它的子节点相关联的数据。这就好像是一个文件系统,只不过文件系统中的文件还可以具有目录的功能。另外,指向节点的路径必须用规范的绝对路径来表示,并且以斜线“/”来分割。需要注意的是,在ZooKeeper中不允许使用相对路径。

1)Znode

ZooKeeper目录树中的每一个节点对应着一个Znode。每个Znode维护着一个属性结构,它包含数据的版本号(dataVersion)、时间戳(ctime、mtime)等状态信息。ZooKeeper正是使用节点的这些特性来实现它的某些特定功能的。每当Znode的数据改变时,它相应的版本号将会增加。每当客户端检索数据时,它将同时检索数据的版本号。并且如果一个客户端执行了某个节点的更新或删除操作,它也必须提供要被操作的数据的版本号。如果所提供的数据版本号与实际的不匹配,那么这个操作将会失败。

Znode是客户端要访问的ZooKeeper的主要实体,它包含以下几个主要特征:

(1) watches

客户端可以在节点上设置watch(我们成为监视器)。当节点的状态发生改变时(数据的增、删、改等操作)将会触发watch对应的操作。当watch被触发时,ZooKeeper将会向客户端发送仅发送一个通知,因为watch只能被触发一次。

(2)数据访问

ZooKeeper中的每个节点上存储的数据需要被原子性的操作。也就是说,读操作将获取与节点相关的所有数据,写操作也将替换节点的所有数据。另外,每一个节点拥有自己的ACL(访问控制列表),这个列表规定的用户的权限,即限定了特定用户对目标节点可以执行的操作。

(3) 临时节点

ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。ZooKeeper临时节点的生命周期依赖于创建于它们的会话。一旦会话结束,临时节点将被自动删除,当然也可以手动删除。另外,需要注意的是,ZooKeeper的临时节点不允许拥有子节点。相反,永久节点的生命周期不依赖与会话,并且只有在客户端显示执行删除操作的时候,它们才被删除。

(4) 顺序节点(唯一性保证)

2)ZooKeeper中的时间

ZooKeeper中有多种记录时间的形式,其中包括如下几个主要属性:

(1) Zxid

(2) 版本号

对节点的每一个操作都将致使这个节点的版本号增加。每个节点维护着三个版本号,他们分别为:version(节点数据版本号)、cversion(子节点版本号)、aversion(节点所拥有的ACL的版本号)。

3)、节点属性结构

通过上面的介绍,我们可以了解到,一个节点自身拥有表示其状态的许多重要属性。下表给出了详细的介绍:

属性 描述
czxid 节点被创建的Zxid值
mzxid 节点被修改的Zxid值
ctime 节点被创建的时间
mtime 节点最后一次被修改的时间
versoin 节点被修改的版本号
cversion 节点的所拥有子节点被修改的版本号
aversion 节点的ACL被修改的版本号
emphemeralOwner 如果此节点为临时节点,那么它的值为这个节点拥有者的会话ID;否则,它的值为0
dataLength 节点数据域的长度
numChildren 节点拥有的子节点个数

2、ZooKeeper会话及状态

ZooKeeper客户端通过句柄为ZooKeeper服务建立一个会话。这个会话一旦创建,句柄将以CONNECTING状态开始启动。客户端尝试连接到其中一个ZooKeeper服务器,如果连接成功,它的状态将变为CONNECTED。在一般情况下只有上述这两种状态。如果一个可恢复的错误发生,比如会话终结或认证失败,或者应用程序明确地关闭了句柄,句柄将会转入关闭状态。

为了创建一个客户端会话,应用程序必须提供一个由主机(IP或主机名)和端口所组成的连接字符串,这个字符串标识了要连接的目标主机及主机端口。ZooKeeper客户端将选择服务器列表中的任意一个服务器并尝试连接。如果连接失败,那么客户端将自动尝试连接服务列表中的其他服务器,直到连接成功。

3、ZooKeeper watches

ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()、getChildren()以及getData()。watch事件是一次性的触发器,当watch的对象状态发生改变时,将会触发此对象上所设置的watch对应的事件。

在使用watch时需要注意,watch是一次性触发器,并且只有在数据发送改变时,watch事件才会被发送到客户端。例如:如果一个客户端进行了getData("/znode1", true)操作,并且只有"/znode1"的数据被改变或删除了,那么客户端将获得一个关于“znode1”的时间。如果/znode1再次改变,那么僵不再有watch事件发生给客户端,除非客户端为另一个读操作重新设置了一个watch。

watch事件将被异步地发生到客户端,并且ZooKeeper为watch机制提供了有序的一致性保证。理论上,客户端接收watch的事件的时间要快于其看到watch对象状态变化的时间。

ZooKeeper所管理的watch可以分为两类:一类是数据watch(data watches);一类是子watch(child watches)。getData()和exists()负责设置数据watch,getChildren()负责设置子watch()。我们可以h通过操作返回的数据来设置不同的watch。getData()和exists()返回关于节点数据的信息,getChildren()返回孩子列表。因此,setData()将触发设置了数据watch的对应事件。一个成功的create操作将触发Znode的数据watch,以及孩子watch。一个成功的delete()操作将触发数据watch和孩子watch,因为Znode被删除的时候,它的child watch也将被删除。

watch由客户端所连接的ZooKeeper服务器在本地维护,因此watch可以非常容易第设置、管理和分派。当客户端连接到一个新的服务器上时,任何的会话事件将可能触发watch。另外,当成服务器断开的时候,watch将不会被接收。但是,当一个客户端重新建立连接的时候,任何先前注册过的watch都会被重新注册。

4、ZooKeeper ACL

ZooKeeper使用ACL来对Znode进行访问控制。ACL的实现和UNIX文件访问许可非常相似:它使用许可位来对一个节点的不同操作进行运行或者禁止的权限控制。但是,和标准UNIX不同的是,ZooKeeper节点有user(文件的拥有者)、group和world三种标准模式,并且没有节点所有者的概念。

需要注意的是,一个ACL和一个ZooKeeper节点相对应。并且,父节点的ACL与子节点的ACL是相互独立的。也就是说,ACL不能被子节点所继承,父节点所拥有的权限与子节点所拥有的权限没有任何关系。

下表为访问控制列表所规定的权限:

权限 权限描述
CREATE(创建) 创建子节点
READ(读) 从节点获取数据或列出节点的所有子节点
WRITE(写) 设置节点的数据
DELETE(删除) 删除子节点
ADMIN(管理员) 可以设置权限

ZooKeeper ACL的使用依赖于验证,它支持如下几种验证模式:

world:代表某一特定的用户(客户端);

auth:代表任何已经通过验证的用户(客户端);

digest:通过用户名密码进行验证;

ip:通过客户端IP地址进行验证。

 另外,ZooKeeper Java API支持三种标准用户权限,它们分别是:

ZOO_OPEN_ACL_UNSAFE;ZOO_READ_ACL_UNSAFE;ZOO_CREATOR_ALL_ACL;

第一种对于所有的ACL来说都是完全开放的:任何应用序可以在节点上执行任何操作,比如创建、列出并删除子节点。第二种对于任意的应用程序来说,仅仅on具有读权限。第三中授予节点创建者所有的权限。需要注意的是,在设置此权限之前,创建者必须已经通过了服务器的认证。

5、ZooKeeper的一致性保证

ZooKeeper是一种高性能、可扩展的服务。ZooKeeper的读写速度非常快,并且读的速度要比写更快。另外,在进行读操作的时候,ZooKeeper依然能够为旧数据提供服务。这些都是由ZooKeeper所提供的一致性保证的。它具有如下特点:

(1) 顺序一致性

客户端的更新顺序与它们被发送的顺序相一致

(2) 原子性

更新操作要么成功,要么失败,没有第三中结果

(3) 单系统镜像

无论客户端连接到哪一个服务器,他将看到相同的ZooKeeper视图。

(4) 可靠性

一旦一个更新操作被应用,那么在客户端再次更新之前,其值将不会改变。这会保证产生下面两种结果:

如果客户端成功地获得了正确的返回代码,那么说明更新已经成功。如果不能够获得返回代码(由于通信错误),那么客户端将不知道更新操作是否生效。

当故障恢复的时候,任何客户端能够看到的执行成功的更新操作将不会回滚。

(5) 实时性

在特定的一段时间内,客户端看到的系统需要被保证是实时的(在十几秒时间里)。在此时间内,任何系统的改变被客户端看到,或者被客户端侦测到。

这些一致性得到保证后,ZooKeeper更高级功能的设计与实现将会变得非常容易,例如:leader选举、队列、以及可撤销等机制的实现。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐