zookeeper是一个开源的分布式协调服务.是典型的分布式数据一致性的解决方案.
zookeeper可以保证以下分布式一致性的特性
1. 顺序性:同一客户端发起的事务请求,最终会严格的按照发出顺序应用到zookeeper上
2. 原子性:事务请求的执行结果在集群机器上要么全部成功,要么全部失败,不存在部分成功,部分失败的结果.
3. 单一视图:客户端无论连接到哪个zookeeper服务端,所看到的服务端数据模型都是一致的.
4. 可靠性:一旦服务端成功的应用了一条事务,而且完成了对客户端的响应.那么这个事务对服务端的状态变更就会被持久化.
5. 实时性:一旦一个事务被成功的应用了,那么客户端能从服务端上读取事务变更后的最新的数据状态.这里需要注意的是,zookeeper仅保证在一段时间内,客户端最终一定能够从服务端上读取到最新的数据状态.

zookeeper基本概念

zookeeper架构

系统模型如下图所示

zookeeper 事务与作用 zookeeper 事务请求_一致性

  1. 客户端随机连接集群中任何一台server
  2. 集群内所有server基于Zab(ZooKeeper Atomic Broadcast)协议进 行通信
  3. 集群内部根据算法自动选举出一个leader,负责向follower(其他 server)广播所有变化消息
  4. 集群中每个follower都和leader通信
    • Follower接收来自leader的所有变化消息,保存在自己内存
    • Follower转发来自客户端的写请求给leader
    • 客户端的读请求会在follower端直接服务,无需转发给leader

集群角色

Leader
Leader服务器是zookeeper集群工作机制的核心.
事务请求的唯一调度者和处理者,保证集群事务请求处理的顺序性.

Follower
Follower服务器是zookeeper集群状态的跟随者.
处理非事务请求,转发事务请求给Leader服务器
参与事务请求的proposal投票
参与Leader选举投票

Observer
Observer服务器只提供非事务服务.通常用于不影响集群事务处理能力的前提下提升集群的非事务的处理能力

zookeeper数据模型

  1. 基于树形结构的命名空间,与文件系统类似
  2. 节点(znode)都可以存数据,可以有子节点
  3. 节点不支持重命名
  4. 数据大小不超过1MB(可配置)
  5. 数据读写要保证完整性

zookeeper 事务与作用 zookeeper 事务请求_zookeeper_02

ZooKeeper基本API

string create(path, data, acl, flags)

delete(path, expected_version)

stat setData(path, data, expected_version)

(data, stat) getData(path, watch)

stat exists(path, watch)

string[] getChildren(path, watch)

数据节点

Zookeeper把所有的数据保存到内存中,数据模型就是一颗树(znode tree).由斜杠(/)进行分割路径,就是一个znode,如/foo/path1.每个znode上都会保存自己的数据内容,同时还会保存一系列的属性.

节点信息
[zk: localhost:2181(CONNECTED) 4]
get /YINSHI.MONITOR.ALIVE.CHECK
?t 10.232.102.191:21811353595654255
cZxid = 0x300000002
ctime = Thu Dec 08 23:29:53 CST 2011
mZxid = 0xe00008bbf
mtime = Thu Jul 28 07:17:34 CST 2012
pZxid = 0x300000002
cversion = 0
dataVersion = 2164293
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 39
numChildren = 0

上面这个信息,是在ZK命令行的一个输出信息,从这个输出内容中可以清楚的看到,ZK的一个节点包含了哪些信息。其中比较重要的信息包括节点的数据内容,节点创建/修改的事务ID,节点/修改创建时间,当前的数据版本号,数据内容长度,子节点个数等。

版本
zookeeper的每个znode都会存储数据.zookeeper都会为每个znode维护一个叫stat的数据结构.stat记录了znode的三个数据版本.分别是cversion ,aversion,dataVersion.
dataVersion:当前数据节点数据内容的版本.注意这里关注的是节点数据内容的变更次数,强调的是变更次数,即使两次变更的数据内容的值没有发生变化,dataVersion的值仍然会发生变化.
cVersion:当前数据节点子节点变更版本号.
aVersion:当前数据节点acl变更版本号

Znode节点类型

  1. Sequential节点和non-sequential节点
  2. Ephemeral节点和persistent节点
Sequential/non-sequential节点类型
  1. Non-sequential节点不能有重名
  2. Sequential节点
    • 创建时可重名
    • 实际生成节点名末尾自动添加一个10位长度、左边以0填充的单调递增数字

zookeeper 事务与作用 zookeeper 事务请求_一致性_03

Ephemeral/Persistent节点类型
  1. Ephemeral节点在客户端session结束或超时后自动删除
  2. Persistent节点生命周期和session无关,只能显式删除

正常连接时节点情况:

zookeeper 事务与作用 zookeeper 事务请求_一致性_04

断开客户端连接时节点情况:

zookeeper 事务与作用 zookeeper 事务请求_zookeeper 事务与作用_05

ZooKeeper Session

  1. 客户端和server间采用长连接
  2. 连接建立后,server产生session ID(64位)返还 给客户端
  3. 客户端定期发送ping包来检查和保持和server的 连接
  4. 一旦session结束或超时,所有ephemeral节点会 被删除
  5. 客户端可根据情况设置合适的session超时时间
  6. 客户端能够异步接收来自服务端的Watcher事件通知

Session指的是客户端会话.一个客户端连接指的是客户端跟服务端之间建立起的一个TCP长连接.默认端口为2181.从第一次创建连接开始,session的会话周期就开始了,sessionTimeout是用于设置客户端会话超时时间,当由于服务器压力太大,网络故障或客户端主动断开连接等各种原因导致的客户端连接断开时,只要在sessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效.

ZooKeeper Watches

  1. Watch是客户端安装在server的事件侦听方法
  2. 当侦听的变化发生时,server发消息给客户端进行通知
  3. 客户端使用单线程对所有事件按顺序同步回调
  4. 触发回调条件:
    客户端连接、断开连接
    节点数据发生改变
    节点本身发生变化(包括自身节点的删除或者子节点列表变化)
  5. Watch是单发的,每次触发后会被自动删除
  6. 如果需要再次侦听事件,必须重新安装 watch
  7. 无法保证跟踪到每一个变化
  8. 避免安装大量watches侦听在同一个节点

Watch的创建和触发规则

zookeeper 事务与作用 zookeeper 事务请求_zookeeper 事务与作用_06

zooKeeper中所有的读操作—getData(), getChildren(), exists()—都有一个选项:设置一个监视器,作为附带的功能。ZooKeeper监视器的定义如下:一个监视器事件是一个一次性触发事件,它被发送到设置它的客户端,它发生的条件是它监视的数据发生变化了。关于监视器的定义,这里有3个关键点需要考虑:
1:一次触发
当数据发生变化时,监视器事件被发送到客户端。例如,如果客户端执行getData(“/znode1”, true),而后来/znode1的数据变化了或删除了,客户端就会得到一个/znode1变化的监视器事件,如果/znode1又发生了变化,不会发送监视器事件,除非该客户端再次执行读操作而设置了一个新的监视器。
2:通知发送给客户端
Zookeeper 客户端和服务端是通过 socket 进行通信的,由于网络存在故障,所以监视事件很有可能不会成功地到达客户端,监视事件是异步发送至监视者的,Zookeeper 本身提供了保序性(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的 znode 发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event). 网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序。

3:被设置 watch 的数据
这意味着 znode 节点本身具有不同的改变方式。
你也可以想象 Zookeeper 维护了两条监视链表:数据监视和子节点监视(data watches and child watches) getData() and exists() 设置数据监视,getChildren() 设置子节点监视。

ACL(Access control list)

为有效的保障zookeeper中数据的安全,从而避免误操作导致分布式系统运行异常.
ZooKeeper有一套完善的ACL权限控制机制来保证数据的安全
用权限模式(schema):授权对象(ID):权限(permission)来标识一条有效的ACL信息.
ZooKeeper支持以下权限:
•CREATE: 能创建子节点
•READ: 能获取节点数据及列出它的子节点
•WRITE: 能设置节点数据
•DELETE: 能删除子节点
•ADMIN: 能设置权限
CREATE和DELETE权限从写权限中分离出来,为的是获得更好的访问控制。运用CREATE和DELETE的场合如下:你想让A用户能够设置节点数据,但不允许创建或删除子节点。

一条ACL只针对一个znode,即它不适用于子节点.例如,如果/app只对ip:172.16.16.1可读,而/app/status对任何人可读,ACL不是递归的。