初识Zookeeper以及其中的选举流程

543 阅读6分钟

知之为知之,不知为不知,是知也。

01、角色

  • Leader:

主要负责处理事务相关的操作,负责给Follower发布命令,处理Follower的反馈信息

负责同步消息,将消息同步到Follower中

可以保证事务处理的顺序性

负责投票的发起以及更新系统的状态

  • Follower:

负责参与投票选举Leader

参与事务的Proposal请求的投票

将事务的执行结果反馈给Leader

  • Observer:

作为观察者不参与Leader的选举

负责将客户端的写请求转发给Leader

02、会话

  • 会话是指zookeeper服务器与客户端的会话,在zookeeper中一个客户端连接是指客户端与服务端之间的TCP长连接。

  • 客户端启动时首先会与服务器简历一个TCP建立一个连接,从建立这个连接开始,客户端会话的生命周期就开始了。

  • 通过这个连接客户端可以通过心跳检测来保证与服务端之间的会话,也能够向zookeeper服务器发送请求并接受响应,还可以接收服务器的Watch事件通知。

  • 如果因为故障等原因导致客户端连接断开,那么在sessionTimeout规定的时间内能够重新连接上集群中的任意一台,那么之前的会话仍然有效。

  • 为客户端创建连接之前服务端会为客户端分配一个sessionID,并且sessionID是唯一的。

03、节点

  • 临时节点:临时节点的生命周期和客户端与服务端的会话进行保定,如果客户端会话失效,那么这个客户端创建的所有临时节点也会被移除。

  • 持久节点:一旦ZNode被创建除非执行ZNode移除操作,否则ZNode一直保存在zookeeper上。

  • zookeeper将数据都保存在内存中,保存数据的模型是以一棵树的形式进行保存的

  • 在ZNode中,zookeeper都会为每个ZNode维护一个叫做Stat的数据结构,Stat中记录ZNode的三个数据版本,分别是:

        1、version(当前ZNode版本)

        2、cversion(当前ZNode子节点的版本)

        3、aversion(当前ZNode的ACL版本)

04、Watcher(监听)

  • 用户使用zookeeper时可以在指定节点上注册Watcher,并且当有特定事件触发了这个Watcher时,zookeeper服务端会将这个事件通知到指定的客户端中。

  • watch事件是一次性的,触发结束就会消失。

  • 流程如下:

Watch是轻量级的,其实就是本地JVM的Callback,服务器端只是存了是否有设置了Watcher的布尔类型。(源码见:org.apache.zookeeper.server.FinalRequestProcessor)

在服务端,在FinalRequestProcessor处理对应的Znode操作时,会根据客户端传递的watcher变量,添加到对应的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化

Leader通过投票通过了某次Znode变化的请求后,然后通知对应的Follower,Follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper客户端。

Zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。

05、ACL

zookeeper采用了ACL策略来实现权限控制,这个ACL策略类似于UNIX文件系统的权限控制。

五种权限分别为:

1、CREATE:创建子节点的权限

2、READ:读取节点数据以及子节点列表的权限

3、WRITER:更新节点数据的权限

4、DELETE:删除子节点的权限

5、ADMIN:设置节点ACL的权限

06、特点

1、顺序一致性:客户端发出的请求会按照发出的顺序发送给zookeeper

2、原子性:zookeeper集群要处理某个事务请求时,该事务在集群中所有的处理结果都是一致的,也就是要么该事务被所有zookeeper处理成功,只要有一个zookeeper没有处理成功就全部失败。

3、可靠性:一旦请求被应用,那么该请求的结果就会被持久化,直到下一次的请求。

4、数据唯一性:在集群中客户端无论连接了哪个zookeeper获取到的数据模型都是一样的。

07、Zookeeper选举流程

  • zookeeper集群一般都是奇数台,这是因为如果有三台集器,那么最多允许挂掉一台,如果有四台,那么也是最多允许挂掉一台,既然三台 和四台的容灾能力是一样的,那么为了节省服务器资源选择奇数个数就可以。

  • 在zookeeper集群中只要有任意一台机器收到了半数以上的投票,那么该机器就被选举为Leader。

  • zookeeper的选举通常是由zxid以及myid来决定谁是Leader。

  • zxid:zxid是一个64位的有规则的编号,在64位中高32位是epoch编号,低32位是消息计数器,每收到一条提议(proposal),低32位的消息计数器就会加1。epoch编号是选举Leader的计数器,也就是每次投票选举Leader操作都会进行加1。每产生一个Leader那么epoch都会加1并且保证了唯一性,这样也保证了Follower只听从最新的epoch编号对应的Leader,就算旧的Leader崩溃恢复之后也不会有其它Follower听从这个旧Leader了。

  • myid:myid是集群中的机器标识,在集群中每个机器都会分配一个唯一的myid。

  • 投票过程:在集群中每个启动的server的状态都是LOOKING,然后开始执行选举,每个server都会向其它server广播投票,投票信息中包含该server的myid和zxid(刚开始时myid和zxid都是自己),比如server1投的信息为(1,0),server2投出的信息为(2,0),server3投出的为(3,0)然后首先根据zxid来选举谁是Leader,发现zxid都相同,那么再根据myid,server1收到server2和server3的信息,那么根据myid会投票server3为Leader,server2收到server1和server3的,那么也会投票server3,server3收到的投票超过半数,则选择server3为Leader,最后立即改变集群中各个server的状态都为Following。(举例比较单一也是为了方便理解,真实的投票选举过程可以看paxos算法选举流程)

08、zab协议

1、崩溃恢复:当集群中Leader宕机或者半数以上的Follower失去连接,那么此时Leader就不是一个合法的Leader就需要重新选举Leader,就需要进入崩溃恢复阶段,崩溃恢复阶段包括两部分:Leader选举和数据同步,Leader选举阶段负责选举新的Leader,数据同步阶段负责将Follower和Leader中的数据保持一致。

2、消息广播:

1、Leader收到客户端的事务请求时会将该请求转换为proposal,并且会为proposal生成一个唯一的zxid

2、Leader会为每一个Follower生成一个FIFO队列,用来存储Leader发出的proposal,并且Follower会按照FIFO顺序接收(保证顺序性)

3、Follower收到proposal然后将proposal写入本地磁盘中,写入成功后返回一个ack响应消息给Leader。

4、Leader收到超过半数的ack响应消息后,则认为消息发送成功,可以commit事务

5、Leader向所有的Follower发送commit消息,同时自身也会完成事务的提交。Follower收到commit消息则将proposal事务提交。