Zookeeper 编程指南官网文档学习笔记
此文是link zk program guide的阅读笔记。
由于对原文中出现的watches还没有很好的理解,在翻译时结合了上下文和自己的理解有时翻译成监听,有时翻译成事件。待我完全理解后再来修改一番。
四个关于zk的概念
- 数据模型
- zk会话
- zk监听
- 一致性保证
zk数据模型
zk拥有一个层次结构的命名空间(树形结构),更像是一个可以附带信息的分布式文件系统,在zk中,没有相对引用(相对路径?)的概念,在路径中可以使用unicode字符,但是需要注意下列情况:
- 不能使用\u0000字符(在C里面会出现问题)
- \u0001 - \u001F 和 \u007F - \u009F 显示有问题
- \ud800 - \uF8FF 和 \uFF0 - \uFFF 不允许使用
- .和..可以出现在路径中,但是不能单独出现在路径中
- zookeeper是保留关键字,请避免使用
ZNodes
在zk中,所有节点都是znode, znode维护着节点的统计信息,包括版本号,acl changes,统计信息与时间戳关联,每次更新节点信息的时候,版本号+1,当客户端请求节点的时候,服务器同时将版本信息发送过去,当客户端需要更改节点信息的时候,附带将节点的版本号发送到服务器,服务器发现如果客户端提供的版本号和服务器现有节点的版本号不一致的话, 拒绝更新操作。理由很简单,为了避免数据覆盖问题
In distributed application engineering, the word node can refer to a generic host machine, a server, a member of an ensemble, a client process, etc. In the ZooKeeper documentation, znodes refer to the data nodes. Servers refer to machines that make up the ZooKeeper service; quorum peers refer to the servers that make up an ensemble; client refers to any host or process which uses a ZooKeeper service.
ZNode是zk编程最主要的访问对象,有以下特点:
- Watches:可以为znode设置一个watches(监听器?),当znode更新的时候触发watches,发送通知给客户端,然后清除watches。
- 数据访问:对于存储在znode上的数据的读写都是原子的,读写都会更新节点的所有信息,每个znode会使用ACL来做访问控制
zk不是数据库,虽然zk可以存储数据,但是不要把太多的存储数据放在zk上面,znode的数据大小限制是1M,但是建议不要存储太多信息,否则会导致更大的延时。一般来说,zk的用法是存储一些配置,集群状态的信息,如果需要存储较多的数据,可以把数据存在HDFS或NFS,然后把指针存在zk中
- 临时性znode:在zk会话存在期间才存在的znode,如果会话停止了,那么znode也被删除了。临时性的znode不允许有子节点
- 序列节点:创建znode的时候,可以要求zk为路径后面附上一个单调递增的计数器,这个计数器的格式这样的 %010d,这个计数器是由父znode维护的一个signed int,最大值2147483647
zk时间
- Zxid:用来标记zk状态的更新,如果zxid1 小于 zxid2, 就说明zixd1的更新早于zxid2
Version Numbers:用来标记一个znode的更新版本信息,每个znode有三个version numbers,分别是:
- version:znode数据的版本号
- cversion:子znode的版本号
- aversion:节点ACL的版本号
Ticks:滴答声,心跳, Tick是时钟(带时针分针的那种)运行时的滴答声,这里准确的说是一个时间流逝的单位。可以用来定义状态更新,会话或者连接的超时。
- 真实时间:zk除了在创建和更新节点的时间戳的时候不使用真实时间或者时钟时间.
zk统计信息结构
- czxid:导致当前节点创建的更新的zxid
- mzxid:导致当前节点改变的更新的zxid
- ctime:节点创建的时间戳(从1970-1-1 到创建时间的毫秒数)
- version:见上文
- cversion:见上文
- aversion:见上文
- ephemeralOwnwe:见名知意,首先这是一个会话ID,如果当前znode不是临时性节点,那么ID为0,否则是节点拥有者的会话ID
- dataLength:不解释
- numChildren:不解释
zk会话
会话是zk客户端和zk服务端连接的会话
represented as a 64-bit number
状态转移表示如下图:
在需要连接到zk服务器的时候,指定服务器主机可以用英文半角逗号连接,zk客户端会随机选一个连接,如果失败,那么换一个主机连,直到连接上为止。
客户端连接上zk之后,会得到一个一个会话ID 和密码,更换zk主机连接的时候,需要发送会话ID和密码来验证。
建立会话的时候可以附带发送超时参数,最小2,最大20。数字见上文。
另一个简历zk会话的参数是default Watcher(Java 对象实例),在客户端有任何状态改变的时候,watchers将会得到通知,由于程序启动时候还未建立zk会话,所以第一条通知通常是zk会话连接建立的通知。
Zookeeper Watches
Watches 是一个一次性的触发器。Watches的三个关键点:
- 一次性触发:触发之后就清除
- 由服务器发送到客户端:事件是异步的发送到监听器(Watcher)的,zk提供了发送事件的次序保证。
a client will never see a change for which it has set a watch until it first sees the watch event.
- 数据的监听:zk维护着两个监听队列,一个是数据监听,另一个是子节点监听。getDate() 和 exist() 设置数据监听,getChildren()设置子节点监听。
监听的语义
三个调用可以设置监听:exists(), getData(), getChildren().
以下是能够由事件触发的监听器
- Created event:由exists()调用激活
- Deleted event:由exists(), getData(), getChildren()激活
- Changed event:由 exists() 和 getDate()激活
- Child event:由getChildren()激活
监听的删除
可以删除服务器的监听,也可以删除本地的监听。以下是监听被成功删除后会触发的事件。
- Child Remove Event:在调用getChildren()时加入的watcher.
- Data Remove Event:在调用getData() or exists()时加入的watcher
zk为watches提供什么样的保证?
三个大保证:
- 保证事件的次序
- 客户端会在看到znode的新数据之前 看到znode的监听事件,如果客户端有监听该znode的话
- 事件发送的顺序和事件在zk发生的顺序是一样的
关于Watches需要记住的事情
- watches是一次性的
- watches是一次性的,在事件发生和发送一个新的watches请求之间是有延时的,这之间并没有监听器监听znode,有可能发生了多次的更新而客户端并没有收到通知,做好处理这种情况的准备,如果有需要的话。
- watches是一次性的,意味着只能收到一次更新通知。
- 如果掉线了,不会收到通知(==#)
ACL(Access Control List)
zk支持以下的权限控制:
- create : 创建一个子znode
- read:getData 和 getChildren
- write:setData
- delete:delete a child znode
- admin:set permissions
Trouble shooting
1,请确保连接正常
2,请测试zk服务器宕机,服务器能处理宕机情况不代表客户端也能处理服务器宕机的情况,zk客户端lib会收到服务器宕机的事件通知,此时连接会断开,lib会重新连接服务器,请确保客户端程序在此情况的健壮性。
3,确保主机名正确,不要把不是zk server的主机写到连接字符串里面。
4,小心处理事务日志,因为服务器必须在事务日志持久化成功之后才返回结果,如果持久化存储媒介有问题,会造成应用的性能问题。
5,正确设置Java最大堆空间,在zk中,一切都是有序的,如果一个request需要查找磁盘,那么接下来的其他request也要查找磁盘(并不理解这是为什么)。尽量避免内存数据被swapping到磁盘上面。总结:heap size 尽可能的大