目的
通过共享存储,实现分布式系统的任务协调。
以共享存储,data tree为基础,开发者可以在zookeeper上实现分布式锁,主从架构等。
保障AP
基本模型
存储
类文件系统,data tree。data tree 上的节点 – ZNode。ZNode 可以存储 data bytes
Znode 类型
- PERSISTENT
- PERSISTENT_SEQUENTIAL SEQUENTIAL的名字会在父节点下自增,如 worker-1, worker-2…
- EPHEMERAL 临时节点,随session 失效而被删除
- EPHEMERAL_SEQUENTIAL
- CONTAINER 当子节点都被删除后,Container 也随即删除
- PERSISTENT_WITH_TTL 超过TTL 未被修改,且没有子节点
- PERSISTENT_SEQUENTIAL_WITH_TTL
Znode stat
Znode 存储的一些元数据
czxid – znode 创建的 zxid
mzxid – modified zxid
pzxid – last modified child zxid
version – count of changes of the data
Watcher
在get数据的同时,可以设置watcher,以便在节点/数据变动时收到通知。
Watcher为单次触发,被触发后会需要再次设置。
Watcher在session过期后会失效,所以连接转移后需要重新注册watcher
数据watcher – exists, getData
子节点watcher – getChildren
ZK协议
Transaction
改变ZK 状态的操作为一个transaction, transaction 具有幂等性。
每个 transaction 拥有leader 为其分配的唯一 zxid
zxid (64bits) = leader epoch (32bits) + counter (32bits)
leader epoch 在每次新leader被选举出来后更新,epoch不同即可视为不同的leader
Leader 选举
vote = (server id(voteid), zxid)
- 所有server以自己的server id和最近的zxid 作为vote,向其他server 进行广播
- 当一个server 收到一个vote 后,如果 voteZxid > myZxid || (voteZxid == myZxid && voteid > mysid),则更新自己的选票为 (voteId, voteZxid),重新进行广播
- 当超过quorum 的server 的选票达成一致之后,即产生新的leader. 其余server 为follower
上述过程使得拥有最新的zxid的sid最大的server 成为leader.
默认FastLeaderElection 等待时间为200ms。可能会由于网络延迟,使得某些server未接受到最长zxid的vote而认为错位的server 为leader。
Zab协议
Zookeeper Atomic Broacast protocol. zookeeper用来在server提交transaction的协议
- Leader 向所有 Follower 发送 PROPOSAL
- Follower 接受 Proposal 后,回复 Leader ACK
- 若收到超过quorum 的ACK (包括leader 自己),则向所有 Follower 发送 COMMIT, Follower 则执行该提案。
Leader变化
新的Leader 由于leader选取的原则,将持有最大的zxid。新leader负责将所有follower同步到最近状态,再接受新的提案。
- follower 状态落后leader不多,发送缺失的事务。
- follower 状态落后太多,直接发送 snapshot 更新整个follower 状态。
Observer
只接受提案,不参与选举。
作用:提高读请求的throughput。follower增加 -> quorum 增加 -> 写throughput下降。
开销:observer增加 -> 消息数增加
故障
Recoverable
Cilent 与server 暂时断开连接后,所有pending 的request 会收到ConnectionLossException。Client 会自动尝试重新连接其他的server。
Unrecoverable
Client的session被server关闭,或者验权失效。
可以处理好当前工作后,重启该client 解决
外部资源
client可能由于JVM停顿等原因,失去了Leadership,在没有察觉到Leadership 已经失去的情况下,访问改变外部资源,从而导致外部状态不一致。
可以通过在访问外部资源协议中,加入zxid校验,保障旧的leader 不会再新leader 之后再访问资源。
需要注意的细节
顺序保障
写顺序
所有server保证和leader的写操作的顺序一致,但是写操作不能保证在所有server上同时发生,所以不同的server的状态可能会存在短暂的不一致。
读顺序
client观测到的读的顺序也是一致的,但有状态变化有先后。
watcher
在同一个Znode 上设置大量的Watcher 会导致触发大量的通知消息。
Znode
数据上限
默认为1MB, 包括znode byte data 和子节点。
version
znode 重建后,data version 会重新计算。依靠match data version进行的操作可能不可靠。
组件
RequestProcessor
server 由 RequestProcessor 所组成的pipeline 来处理 Request object 实现相应功能
LeaderZooKeeperServer
PrepRequestProcessor -> ProposalRequestProcessor -> CommitProcessor -> ToBeAppliedRequestProcessor -> FinalRequestProcessor
ProposalRequestProcessor -> SyncRequestProcessor -> AckRequestProcessor
FollowerZooKeeperServer
FollowerRequestProcessor -> CommitProcessor -> FinalRequestProcessor
SyncRequestProcessor -> SendAckRequestProcessor
WatcherManager
管理Watcher
ExpiryQueue
SessionTrackerImpl 使用ExpiryQueue 以bucket 为单位过期session
Client
Zookeeper 提供客户端API
ClientCnxn 管理连接到server 的socket
Jute
序列化