Zookeeper 开发引言翻译

Zookeeper

概念


1. ZNodes - The Zookeeper Data Model

Zookeeper 有一个类似于分布式文件系统的树状的命令空间。唯一不同是每个节点和他们的子节点可以拥有关联数据。类比到文件系统,就好像允许一个文件同时也是路径。Zookeeper的
路径是约定 绝对的 / 分隔的路径,这里没有相对引用。任何unicode编码的字符可以被用在path中,除了一些约束。

  • ZNodes

Zookeeper 树的每一个节点被当作一个znode.Znodes 很多状态结构,包括 记录数据变化的版本号,ACL(Access Control List) 变化和时间戳。版本号和时间戳允许Zookeeper 验证缓存和协调更新。
每次znode数据变化,版本号都会自增1.例如,当一个客户端遍历数据是,他同事会遍历数据的版本号。同时当客户端更新或者删除数据时,它必须提供它改变目标的znode 数据的版本号。如果提供的
版本号和数据的真是的版本号不匹配,那个更新将会失败。

Watches – 客户端可以在Znode上设置监视器(Watchers)。改变那个znode将会触发watch,然后清除watch.当一个watch被触发,Zookeeper将会给客户端发送一个通知。

Data Access – 在命令空间上每个znode存储的数据可以被自动读写。读 得到这个znode所有的字节数据,写 替换所有的数据。没有znode都会有一个ACL(访问控制列表)来显示谁可以做什么。
Zookeeper 并不是被设计用来做一个通用的数据库或者一个大的对象存储。Instead, it manages coordination data(反而,它管理协调数据)。
This data can come in the form of configuration, status information, rendezvous, etc.
多种形式的协调数据的一个共同也正是他们相对而言都比较小,以KB计算。zookeeper的客户端和服务端实现有一个明智的检查来确保每一个节点的数据小于1M,但是数据的平均大小要少的多。
在一个相对较大的数据上操作将会导致一些操作会话费比较多的时间,同时因为需要在网络和存储媒体上传播移动带来的额外时间可能会带来延迟。如果一个大的数据存储是必须的,那么通常情况处理这些数据
的方式是存储他们在bulk storage system,例如 NFS 或者 HDFS ,然后把指向存储位置的指针放到zookeeper中。

Ephemeral Nodes – 临时结点 Zookeeper还有一个临时节点的概念。这些节点在创建这些节点的session的活动周期中存货。当session结束,这些节点也被删除了。因此。临时节点不允许有子节点。

Sequence Nodes – Unique Naming 顺序节点-唯一命名 当创建一个节点时,你也可以请求Zookeeper给path的结尾添加一个单调递增的计数器。这个计数器对于父节点是独一无二的。
计数器是%010形式,10个数字,先导0填充(这样设计是为了方便排序,eg:0000000001)。记住,用来存储下一个序列的节点是一个有符号的整形术,当超过 2147483647时计数器将会溢出

Container Nodes – 容器节点 zookeeper在3.6版本后加入容器系欸按的概念。容器节点是有特别目的的节点,当作为leader 锁是很有用。当容器的最后一个节点被删除,这个容器编程候选删除项,
将会在未来的某个时间点被删除。鉴于这个属性,当你创建子节点而不是容器节点时,你应该有所准备得到 keeperException.NoNodeException 。所以,当你创建子节点而不是容器节点时,你总是需要
先检查一下 KeeperException.NoNodeException,当确实有异常被捕获时间,你需要重新创建容器节点

  • Zookeeper 中的时间

Zxid – Zookeeper 事务id .Zookeeper状态的每次变化都会收到一个zxid(Zookeeper Transaction Id)形式的标记。这表明了zookeeper 变化的总体顺序。每次改变都会有以独一无二的zxid,如果zxid1 小于 zxid2,那么zxid1发生的早。

Version numbers – 版本号 .节点的每次变化都会导致那个节点的版本号自增1。version 表示这个节点的数据的改变的次数,cversion 表示这个节点子节点的改变的次数,aversion 代表这个节点ACL变化的次数

Ticks – 滴答时间 . 当你用多服务器Zookeeper,服务器用ticks 定义时间的时间,例如 状态的上传 session的超时 每个服务连接的超时时间等等。 这个tick时间是最小的session超时时间(2倍的tick time)的间接标识方式。
如果你个客户端请求的session超时时间小于 最小的session超时时间,那么服务器将会告诉客户端 session超时时间事实上是最小的session超时时间

Real time – 实时时间 .Zookeeper除了znode的创建和修改时把时间戳放到znode的状态结构中,不用实时时间或者时钟时间

  • Zookeeper 的 状态结构

每个Zookeeper的节点都有下面一个域组成:

czxid – znode被创建的zxid
mzxid – znode最后一次被修改的zxid
pzxid – znode的子节点最后一次被修改的zxid
ctime – znode被创建时从新时代(1970?)的毫秒数
mtime – znode最后一次被修改时从新时代(1970?)的毫秒数
version – znode数据改变的次数
cversion – znode子节点数据数据改变的次数
aversion – znode ACL 改变的次数
ephemeralOwner – 如果这个节点是临时节点,那么就是这个节点拥有者的session id ;否则,为0
dataLength – znode数据的长度
numChildren – znode子节点的个数


2. Zookeeper Sessions

每一个zookeeper客户端和zookeeper服务之间通过创建语言绑定创建一个handle来建立一个session.一旦被创建,handle 以 CONNECTING 状态启动, 客户端类库尝试连接服务中一个服务器,
在那个节点状态切换为 CONNECTED 状态。日常操作中,状态通常是这两者其中之一。如果一个不可恢复的错误发生,比如session过期 或者验证失败 应用程序显示关闭handle 等等, 那时handle
的状态就转化为 CLOSED 状态了。

session

为了创建客户端session , 程序代码必须提供一个逗号分隔的 host:post 形式的字符串列表,每一次对应一个zookeeper 服务(eg: “127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002”)
zookeeper客户端将会人影挑选一个服务器,尝试连接它。如果链接失败 或者 服务器以某种理由拒绝链接,客户端将会自动尝试连接列表中的下一台服务器,直到一个连接是可以建立的。

From 3.2 一个可选的”chroot”后缀可以被追加到连接字符串后面。类似于unixde chroot命令,当运行这个命令时,就会解释所有的相对于这个root的路径。
eg:”127.0.0.1:4545/app/a” root路径被切换为”/app/a” ,所有的路径将会以此作为根 。”/foo/bar” 就变成了 “/app/a/foo/bar”
这个功能在多用户环境中将会很有用,zookeeper的每个用户将会由不同的根路径。这使得每个用户的代码重用变得很简单,开发时是/ ,当真正部署时用 一个不同的路径

当一个client得到一个zookeeper服务的handle,zookeeper会创建一个session,并用一个64bit的数字代表它,并将这个值复制给client。如果client连接不同的zookeeper服务,它将会把session id
作为握手连接的一部分。作为一种安全措施,服务器为session id 创建一个密码,任何zookeeper 服务器都可以验证它。当client建立session时,密码和session id 一起传递给客户端。
当和一个新的服务器恢复session 时,客户端传递密码和session id 。

zookeeper客户端类库创建session的参数之一是 session的超时时间(毫秒)。客户端发送一个请求超时,服务端返回给他这个超时。当前的实现需要这个时间最小要是2倍的tickTime(在服务端配置中),
最大是20倍的tickTime.Zookeeper 客户端api允许协商超时。

如果一个客户端session从zookeeper集群变成一个分区的,它将开始搜索session创建时指定的服务器列表。最终,当客户端和至少一个服务器的连通性被重新建立,session还是要转化到
CONNECTED状态(在sessionc超时时间内重新连接) 或者转化为 expired过期状态(在超时时间后重新连接)。为了断开连接而创建一个新的连接是不明智的。zookeeper 的客户端将会为你重新连接。
特别的,我们试探性的用内置的客户端烈苦处理事情,类似于”羊群效应” 当你被通知session过期时,会被创建一个新的session

session 的过期是被zookeeper集群所管理的,而不是zk client.当zk client 和zookeeper 集群建立session时,它提供了一个 “timeout”的值在最上面。这个值被集群用来决定客户端session什么时间超时。
集群发生在集群不再特定的session超时周期中受到客户端的信息(no heartbeat).当session过期时,集群将会删除所有属于这个session的临时节点,并且立即通知所有连接(任何watch those node的)客户端这个变化。
在这个节点过期session的客户端依然是断开连接的,所以知道下次重新和集群建立连接才会被通知到。这个客户端依然保持断开连接的状态,直到TCP重新建立,在那个节点 过期session的监视器将会收到”session expired”的通知

过期session 监视器眼中的 过期session的状态转变
1. ‘connected’:session被建立 并且 客户端和集群处于连接中(client/server通信正常运行)
2. client 被集群分区
3. ‘disconnected’:客户端和服务端失去连通性
4. 时间飞逝,’timeout’之后集群将session置为失效,因为client已经失去连接,所有它什么都看不到
5. 时间飞逝,客户端重新获得和集群的网络连接
6. ‘expired’:最终客户端重新连接到集群,它被通知为过期了

另一个zookeeper session建立调用的另一个参数是默认watcher .客户端任何的状态改变,watcher 都会通知。例如,如果 client断开连接,或者客户端session超时 客户端应该考虑初始状态为 disconnected(在
任何状态改变时间被发送到watcher之前)。在这个新的连接用例中,发送给watcher的第一个事件应该是 连接事件。

客户端持续发送的请求是session存活的必要条件。如果一个session在一个周期内是闲置的,这将会导致session超时,所以client将会发送一个PING连接来保证session是存活的。PING请求不仅允许zookeeper服务器
知道客户端依然存活,同时也会客户端验证是否zookeeper服务依然活跃。PING连接的频率足够保守,可以确保这是一个 察觉死连接和重新连接到一个新的server 的 合适时间。

一旦一个服务器连接被成功建立,无论是同步操作 还是异步操作 下面的两种情况都会导致 异常 (in java):
1. 应用程序在一个 不再存活/有效 的session 调用操作
2. 当有一个延迟(pending)操作 zookeeper 客户端和服务器断开连接

from 3.2 SessionMovedException 19.22.0

服务器列表的更新 我们允许客户端提供一个新的 逗号分隔的host:post 连接字符串来更新连接。例如 如果原来有5个host,现在移掉2个,原来连接到3的连接不变;连接到另外两个host的连接将会随机连接到剩下
的3个host.如果连接被关掉,客户端将会用概率算法来选择一个新的server连接。


3. Zookeeper Watcher

在zookeeper中,所有的读操作是有三种 getData() getChildren() 和 exists().wacth在zookeeper中的定义,一个watch时间是一次触发的,当watch的数据被改变时 传递给设置watch的客户端。
watch定义中的三个关键点:

one-time trigger 一次触发器
当数据改变时,一个wathch事件可以被传递给客户端。例如,如果一个客户端调用了 getData(‘/znode1’,’true’) ,然后如果/znode1的数据被改变或者删除,客户端将会收到一个/znode1的时间。如果
/znode1再次改变,将没有watch时间被传递。除非客户端再进行一个读操作,这会隐示的设置一个新的watch

send to the client 发给客户端
一个事件的暗示是给客户端的。watche 是被异步传递的.zookeeper 会保证顺序。 网络延迟或者其他的影响因素将会导致不同的客户端在不同的时间看到watch并返回状态码。关键点是被不同的客户端看到
一切都有一个一致性顺序。

The Data from which the watch was set 被观察的数据
node的改变有两种不同的watch ,一种是data watches ,一种是chrild watches. getData() 和 exists() 设置 dara watches;getChildren() 设置 child Watchers.
通过数据的返回类型也能更好的额理解,getDat() 和 exists() 放回节点data的信息 ,然而 getChildren 返回子节点的列表。所以setData()将会触发data watches 。
create()将会触发当前节点的data watch 和父节点的child watches。delete() 也会触发 data watcher 和 child watch。

watches的元语
Created event : 可以被 exists 触发
Deleted event : 可以被 exists getData getChildren 触发
Changed event : 可以被 exists getData 触发
Child event : 可以被 getChildren 触发

移除watches
我们可以通过removeWatches 来移除注册在节点上的watches.
Child Remove event : 当node被设置getChildren
Data Remove event : 当node被设置exists 或者 getData

zookeeper对于watches的保证


4. zookeeper用ACL实现权限控制

zookeeper 通过ACLs lai kongzhi znode的权限。ACL的实现有点类似于UNIX文件的权限控制,他用允许/不允许多种操哦做来限定node的访问方位。不想标准的UNIXq权限,一个zookeeper节点
没有被区分为三种不同的用户标准组(user group other).zookeeper 没有节点拥有者这个概念,一个ACL指定了id和权限组成的列表集合、

ACL 只对一个节点有效,它不会应用到子节点。ACL不会递归传递的。

zookeeper 支持可插拔式的权限验证模式。Ids的形式通常是scheme:id,

ACL 有 (scheme:expression,perms) 这样键值对组成。eg: (ip:19.22.0.0/16,READ) 授予ip地址以19.22开头的客户端 READ权限。

ACL的权限
CREATE : 你可以创建一个子节点
READ : 你可以得到节点的数据和子节点列表
WRITE : 你可以为节点设置数据
DELETE : 你可以删除子节点
ADMIN : 你可以设置权限

CREATE 和 DELETE 提供了比 WRITE 更为细粒度的权限控制。

ACL 内建的一些元语
world - 代表 任何人
auth - 代表 任何验证通过的用户
digest - 用 usernam额:password 字符串生成MD5 hash 值,那将会用来作为ACL ID 。
ip - 用客户端IP作为 ACL ID
x509 -

可插拔的zookeeper权限验证


5. 一致性保证 Consistency Guarntees

zookeeper 是一个高性能的可扩展的服务。读写操作被设计都很快,尽管读比写快一些。其中的原因是 当在读的时候,zookeeper 可以使用旧数据。zookeeper一致性保证的原因:

Sequential Consistency : 顺序保证。从客户端的更新将会以它们发送的顺序来应用
Atomicity : 原子性 更新要么成功要么失败,没有其他结果
Single System Image : 无论客户端连接到那个服务器,他看到的将是一样的数据
Reliability : 可靠型。一旦一个更新被应用。 两个推论 …
Timeliness :

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章