zookeeper 核心
- Zookeeper数据模型
- Zookeeper会话
- Zookeeper Watches
- 一致性保证(分布式事务涉及)
zookeeper 数据模型
定义
是zk的分层的命名空间。类似分布式文件系统。命名空间的每个节点既可以关联数据,又可以关联目录。并且路径节点总是通过斜线”/”分隔
znodes
概念
zk中的每个节点都被称为znode。
znode维护一个stat结构(包括数据变化的版本号、访问控制列表变化和时间戳)
作用
版本号和时间戳可以让zk验证缓存和协调更新。znode的数据只要发生了变化,版本号就会增加。
当客户端执行更新或删除时,客户端必须提供他正在改变的znode的版本号。如果它提供的版本号和真实的数据版本号不一致,更新将会失败(行为可能被覆盖)
对zk进行编程主要是对znode作为主体操作
关于node的扩展
在分布式应用工程中,node可以指的是一般的主机,一个服务器,全体成员的一员,一个客户端程序,等等。在Zookeeper的文档中,znode指的是数据节点。Servers指的是组成Zookeeper服务的机器;quorum peers 指的是组成全体的servers;client指的是任何使用Zookeeper服务的主机和程序。
znode 基本特征
watches
znode的变化将会触发watches后清除watches。触发watches时,Zookeeper向客户端发送一个通知
数据访问
- 命名空间里的每个znodes上的数据存储都是原子性的读取和写入。
- 读取时获取所有与znode有关的数据字节,写入时替换所有的数据字节。
- 每个节点通过访问控制列表进行限制访问
- zk不用来存储数据,只是用来管理协调数据。数据形式可以是配置表单,状态信息,集合点等
- 各种形式的协调数据属性都非常小
- 如果需要大数据存储,通常的做法是将数据存储进大存储器系统,如NFS和HDFS,然后将存储指针和地址存储进Zookeeper
临时节点
znode一旦session创建就存在,session结束就被删除
临时节点不可以有子节点
序列节点
- 当创建znode的时候你还可以请求在路径的最后追加一个单调递增的计数器
- 计数器在父节点命名唯一。而且是int类型。
zookeeper 计时
Zxid(事务ID)
每个zk状态的变化都以zxid的形式接收到标记
zx特征:如果zxid1早于zxid2则zxid1一定小于zxid2。并且暴露zk所有变化的总排序
版本号
节点的每个变化都会引起那个节点的版本号的其中之一增加
1.version: 数据变化版本号
2.cversion:子目录变化版本号
3.aversion:访问控制列表的变化版本号
Ticks
- 服务器使用ticks定义事件(如状态上传,会话超时,同事之间的连接超时等)的时间。通常在多服务器中使用
- 如果一个客户端请求会话超时小于最小的会话超时,服务器就会告诉客户端会话超时实际上是最低会话超时时间。
Real Time
zk不使用实时或时钟时间,除了将时间戳加在znode创建和更新的stat结构上。
zookeeper Stat
- czxid - 引起这个znode创建的zxid
- mzxid - znode最后更新的zxid
- ctime - znode被创建的毫秒数(从1970年开始)
- mtime - znode最后修改的毫秒数(从1970年开始)
- version - znode数据变化号
- cversion - znode子节点变化号
- aversion - znode访问控制列表的变化号
- ephemeralOwner - 如果是临时节点这个是znode拥有者的session - id。如果不是临时节点则是0。
- dataLength - znode的数据长度
- numChildren - znode子节点数量
zookeeper 会话
Zookeeper客户端通过使用语言绑定在服务上创建一个handle建立一个和Zookeeper服务的会话
会话成功:handle连接zk服务器。从connection变为connected状态。
会话失败:handle变为closed状态(例如会话超时或授权失败,或应用明确的关闭处理器)
创建客户端会话
以逗号分隔开的host:port的列表
(eg:”127.0.0.1:4545” or “127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002”)
zk会选择任意一个服务并尝试连接它。如果这个连接失败,客户端变为disconected,客户端会自动的尝试连接列表里的下一个服务器,直到建立连接
connectionString+chroot:改变程序执行时所参考的根目录位置
chroot命令的作用
客户端连接zk会话,作为安全措施,需要将sessionId(64位的数字)和密码发送给客户端
当客户端从ZK集群分隔。它将开始搜索在session创建期间指定的服务器列表server.x 。session状态将会从”connected”转为”expired”(重建超时)
zk客户端会自动重连,只有当zk通知session超时才能创建新的session。
zk集群管理session会话
timeout决定会话何时过期。
当集群在指定的session超时周期内没有听到客户端(没有心跳)时发生。
集群会删除全部session的临时节点并立即通知其他客户端(watch这些znode的客户端)。
过期会话状态转化实例通过watcher查看
- ‘connected’:建立session且正在和集群通信
- …客户端从集群分离
- ‘disconnected’:客户端丢失集群的连接
- …时间消失,’timeout’周期之后集群过期session,客户端什么都看不到
- …时间消失,客户端收复集群的连通性
- ‘expired’:最终客户端重连到集群,然后是过期通知
zookeeper Watches
Zookeeper里的所有读取操作都有设置watch的选项 。watch事件是one-time触发,向客户端发送设置watch,当设置watch的数据变化时发生
watch特征
- 一次触发
- 发往客户端
- 为数据设置watch
Watch特征
- Watches和其他事件、watches和异步恢复都是有序的。Zookeeper客户端保证每件事都是有序派发。
- 客户端在看到新数据之前先看到watch事件。
- 对应更新顺序的Zookeeper watches事件顺序由Zookeeper服务所见。
注意:
1. 如果你得到一个watch事件且想在将来的变化得到通知,必须设置另一个watch
2. 因为watches是一次触发且在获得事件和发送请求得到wathes之间有延迟你不能可靠的看到发生在Zookeeper节点的每一个变化
3. 一个watch对象,或function/context对,对于指定的通知只能触发一次。(eg. 如果相同的文件通过exists和getData注册了相同的watch对象并且文件稍后删除了,watch将只会触发文件的删除通知)
4. 从服务端断开连接时(比如服务器故障),将不会得到任何watches直到重新建立连接
zookeeper ACLs
- Zookeeper使用ACLs控制访问它的znodes(Zookeeper的数据节点)
- Zookeeper节点不由三个标准范围(用户,组 和 world)限制。Zookeeper没有znode所有者的概念。而是一个ACLs指定一组ids和与这些ids相关联的权限
- ACL只适用于特定的znode。尤其不适用于children
- ACLs不是递归控制
(eg. 如果/app对ip:192.168.1.56是只读的并且/app/status是全都可读的,任何人可以读取/app/status)- Zookeeper支持可插拔的权限认证方案
ACL权限
- CREATE:可以创建子节点
- READ:可以从节点获取数据并列出它的子节点
- WRITE:可以向节点设置数据
- DELETE:可以删除一个子节点
- ADMIN:可以设置权限
内嵌的ACL schemes
- world:有单独的id,anyone,代表任何人
- auth:不适用任何id,代表任何授权的用户。
- digest:使用username;password字符串生成MD5哈希作为ACL ID身份。通过发送username:password明文授权。在ACL里使用时expression将会是username:base64编码的SHA1 password摘要。
- ip:使用客户端IP作为ACL ID身份。
一致性保证
顺序一致性
客户端的更新将发送到序列
原子性
更新成功或失败 – 没有局部结果
单一系统影像
客户端看到的服务端的视图都一样
可靠性
一旦更新应用了,它将会一直保持到下次更新覆盖。这个保证有两个推论
如果客户端成功,更新就被应用。客户端看不到失败现象。
客户端可以看到任何更新,通过读取请求或成功的更新
时效性系统的客户端视图在特定的时间保证是最新的。
Java
创建Zookeeper的时候,同时创建了两个线程:一个IO线程和事件线程。所有的IO都在在IO线程上(使用Java NIO)。所有的事件回调都在事件线程上。Session在IO线程上维护如重连Zookeeper服务和维护心跳。同步方法调用也在IO线程处理。所有异步调用和watche事件在事件线程上处理