1 简介
Zookeeper是由雅虎创建,Zookeeper并没有直接采用Paxos算法
,而是采用了一种被称为ZAB
(Zookeeper Atomic Broadcast)的一致性协议
。
Zookeeper是一个典型的分布式数据一致性的解决方案
,分布式应用程序可以基于它实现诸如数据发布/订阅
、负载均衡
、命名服务
、分布式协调/通知
、集群管理
、Master选举
、分布式锁
和分布式队列
等功能。
2 Zookeeper基本概念
2.1 集群角色
Leader
:Leader服务器为客户端提供读写服务Follower
:Follower为客户端提供读服务Observer
:Observer为客户端提供读服务,不参与选举Leader,不参与事务投票,不影响写性能提高集群的读性能。
2.2 会话(Session)
Session
是指客户端会话
,是客户端连接服务端的一个TCP长连接
。服务端的Watch事件通知
也是通过该TCP连接
。
2.3 数据节点(Znode)
Zookeeper将所有的数据存储在内存
中,数据模型是一棵树
(Znode Tree),由斜杆进行分割的路径,就是一个Znode
,每个Znode
上都会保存自己的数据内容,同时还会保存一些列的属性信息。
在Zookeeper中,Znode分为持久节点
和临时节点
,持久节点是指一旦创建,除非主动删除,否则这个Znode会一直在Zookeeper中,临时节点它的生命周期是跟会话
绑定,一旦客户端会话失效
,临时节点将会删除
。另外,Zookeeper可以为每个节点添加SEQUENTIAL
属性,一旦有这个属性,那么节点就是一个有序节点
。
- 持久节点(PERSISTENT)(默认):在该数据节点创建后,就
一直存在
与Zookeeper服务器上,直到有删除操作
来主动清除
这个节点。不会因为创建该节点的客户端会话失效而消失; - 持久顺序节点(PERSISTENT_SEQUENTIAL):在ZK中每个
父节点
会为他的第一级子节点
维护一份顺序,用于记录每个子节点创建的先后顺序
; - 临时节点(EPHEMERAL):和持久节点不同,临时节点的生命周期和
客户端会话
绑定。如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非TCP连接断开; - 临时顺序节点(EPHEMERAL_SEQUENTIAL)
2.4 版本
Zookeeper会对每一个Znode维护一个Stat
的数据结构,Stat
中记录了Znode的三个数据版本
,分别是:
version
(当前Znode的版本
)cversion
(当前Znode子节点的版本
)aversion
(当前Znode的ACL版本
)
2.5 Watcher
Watcher
(事件监听器),Zookeeper允许用户在指定节点
上注册watcher
,并且在一些特定事件触发
的时候,Zookeeper服务端会将事件通知
到感兴趣的客户端上去,该机制是Zookeeper实现分布式协调服务
的重要特性。
- 特点
- 一次性:
只触发一次
watches;先注册
再触发
- 异步:
watcher event
异步发送watcher
的通知事件
,即:从server
发送到client
是异步的
;- 只能保证
最终的一致性
。
- 轻量级事件:
Watcher
通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容;- 客户端向服务端注册
Watcher
的时候,并不会把客户端真实的Watcher
对象实体传递到服务端,仅仅是在客户端请求中使用boolean
类型属性进行了标记。
- 客户端串行执行:客户端
Watcher
回调的过程是一个串行同步
的过程。
- 一次性:
2.5.1 工作机制
- 客户端注册 watcher
- 调用
getData()
/getChildren()
/exist()
三个 API,传入Watcher 对象
; - 标记请求
request
,封装Watcher
到WatchRegistration
; - 封装成
Packet 对象
,向服务端发送request
; - 收到服务端响应后,将
Watcher
注册到ZKWatcherManager
中进行管理; - 请求返回,完成注册。
- 调用
- 服务端处理
watcher
- 服务端
接收 Watcher 并存储
:接收到客户端请求,处理请求判断是否需要注册Watcher
,需要的话将数据节点的节点路径和ServerCnxn
(ServerCnxn 代表一个客户端和服务端的连接,实现了Watcher
的process
接口,此时可以看成一个Watcher 对象
)存储在WatcherManager
的WatchTable
和watch2Paths
中去。 - Watcher 触发:以服务端接收到
setData()
事务请求触发NodeDataChanged 事件
为例:- 封装
WatchedEvent
:将通知状态
(SyncConnected)、事件类型
(NodeDataChanged)以及节点路径
封装成一个WatchedEvent 对象
; - 查询
Watcher
:从WatchTable
中根据节点路径查找Watcher
; - 没找到:说明
没有
客户端在该数据节点上注册
过Watcher
; - 找到:
提取
并从WatchTable
和Watch2Paths
中删除
对应Watcher
(从这里可以看出 Watcher 在服务端是一次性的
,触发一次就失效了)
- 封装
- 调用
process 方法
来触发Watcher
:这里process
主要就是通过ServerCnxn
对应的TCP 连接
发送Watcher 事件通知
。
- 服务端
- 客户端回调
watcher
- 客户端
SendThread
线程接收
事件通知,交由EventThread
线程回调Watcher
; - 客户端的
Watcher 机制
同样是一次性的
,一旦被触发后,该 Watcher 就失效了。
- 客户端