【原理】ZooKeeper原理分析

ZooKeeper特性

  • 最终一致性
  • 顺序性
    从同一客户端发起的事务请求,都会最终被严格的按照其发送顺序被应用到zk中。
  • 可靠性
  • 实时性
    zk不能保证多个客户端能同时得到刚更新的数据,所以如果要最新数据,需要在读数据之前强制调用sync接口来保证数据的实时性。
  • 原子性
    要么成功,要么失败。
  • 单一视图
    无论客户端连的是哪个节点,看到的数据模型对外一致。

基础概念

  • SID:服务器ID,即myid
  • ZXID:服务器的事物ID,数据越新,ZXID越大。
  • epoch:逻辑时钟,在服务端是一个自增序列,每一次进入下一轮投票后,值增加1。
  • Server状态
    • Looking:进入选举流程。
    • Following:Leader已经选出,表明当前角色为follower。
    • Observing:当前角色为Observer。
    • Leading:表明当前角色为Leader。

ZooKeeper角色

集群架构图: 

  • Leader,唯一性。
    • 恢复数据
    • 维持与folloer的心跳,接收follower请求并判断follower请求消息类型。
    • follower消息类型主要由PING、REQUEST、ACK、REVALIDATE;PING指follower的心跳信息;REQUEST是follower的提议信息,包括写请求及同步请求;ACK是follower对提议的回复,超过半数follower通过,则commit该提议;REVALIDATE用来延长SESSION有效时间。
  • Follower
    • 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息)。
    • 接收Leader消息并进行处理。
    • 接收Client的请求,如果为写请求,发送给Leader进行投票。
    • 返回Client结果。
  • Observer,与Folloer类似,接收读请求并响应,但无权投票。

数据存储模型

znode,ZooKeeper存储数据模型,类似文件系统的数据模型,具有层级关系的树状结构,每一个znode都可以存储数据和拥有子节点,兼具文件和目录两种特点,如下图:

znode特点

  • 大小上限为1M。
  • 通过路径引用。
  • 四种类型

    • PERSISTENT - 持久化节点
    • PERSISTENT_SEQUENTIAL - 持久化顺序标号节点
    • EPHEMERAL - 临时节点
    • EPHEMERAL_SEQUENTIAL - 临时顺序编号节点

    zookeeper规定,临时节点不可以拥有子节点

  • 顺序节点指在创建时指定一个全局唯一会不断增加的有序编号。

znode属性(zxid)
zxid,用户标识每一次更新操作的Proposal ID。为了保证顺序性,该zkid必须单调递增。zxid使用一个64位的数来表示,高32位是Leader的epoch,从1开始,每次选举出新的Leader,epoch加1;低32位为该epoch内的序号,每次epoch变化,都将低32位的序号重置,其属性细节:

  • czxid:创建节点的事物的zxid
  • mzxid:对znode最近修改的zxid
  • ctime:以距离时间远点(epoch)的毫秒数表示znode的创建时间
  • mtime:以距离时间远点(epoch)的毫秒数表示znode的修改时间
  • version:znode数据的修改次数
  • cversion:znode子节点修改次数
  • aversion:znode的ACL修改次数
  • empemeralOwner:如果znode是临时节点,则表示节点所有者的会话ID;如果不是,则为零
  • dataLength:znode数据长度
  • numChildrem:znode子节点个数

选票数据结构

  • logicClock,即逻辑时钟(epoch),服务器维护的一个自增整数,表示该服务器发起的第多少轮投票
  • state,当前服务器的状态
  • self_id,当前服务器的myid
  • self_zxid,当前服务器上保存的数据的最新zxid
  • vote_id,被推举的服务器的myid
  • vote_zxid,被推举的服务器上所保存的数据的最新zxid

选举过程

  • 状态变更,集群中不存在leader时,所有非Observer的server将自己的服务器状态更为Looking,开始进入Leader的选举流程。
  • 发起投票,每个server产生一个(sid,zxid)的投票,系统初始化的时候zxid均是0;如果是运行期间,每一个server的zxid可能不同,然后将投票发送给集群中的所有server。
  • 接收并检查投票,server接收到投票后,先检查是否是本轮投票,是否来自Looking状态的server。
  • 处理投票,对自己的投票和收到的投票进行PK:

    • 先检查zxid,较大的优先为leader
    • 如果zxid一样,sid较大的为leader

      根据PK结果更新自己的投票,再次发送自己的投票。

  • 统计投票,统计投票信息,如果有过半机器接收到相同的投票,则Leader产生,否则,继续下一轮投票
  • 更新server状态,一旦确定了Leader,server更新自己的状态为Following或者Leading,选举结束。

zookeeper watcher

Watcher主要包括客户端线程客户端WatchManagerZKServer三部分。

如图3,客户端向ZKServer注册Watcher的同时,会将Watcher对象存储在客户端的WatchManager中,当ZKServer触发Watcher事件后,会向客户端发送通知,客户端线程从WatchManager中取出对应的Watcher对象来执行回调逻辑。 watcher回调是通过方法process具体执行。函数process参数WatchedEvent,包含三个基本属性:keeperState(通知状态)、eventType(事件类型)、path(节点路径)。

运行机制

  • Watch是轻量级的,其实就是本地JVM的Callback,服务器端只是存了是否有设置了Watcher的布尔类型。
  • 在服务端,在FinalRequestProcessor处理对应的Znode操作时,会根据客户端传递的watcher变量,添加到对应的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化。
  • Leader通过投票通过了某次Znode变化的请求后,然后通知对应的Follower,Follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper客户端。
  • Zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。

ZooKeeper Session

ZooKeeper客户端通过使用language binding创建服务句柄,与ZooKeeper服务建立会话。一旦创建,句柄就会以CONNECTING状态启动,客户端库会尝试连接到构成ZooKeeper服务的其中一个服务器,此时它将切换到CONNECTED状态。在正常操作期间将处于这两种状态之一。如果发生不可恢复的错误,例如会话到期或身份验证失败,或者应用程序显式关闭句柄,则句柄将移至CLOSED状态。下图显示了ZooKeeper客户端的可能状态转换:

ZooKeeper客户端与服务端保持一个长连接,每隔10s向服务端发送一个心跳,服务器返回给客户端一个响应。一旦session失效,一定时间后就会将session持有的所有Watcher以及瞬时节点删除。

发布了22 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/t1g2q3/article/details/103744962