Zookeeper学习(2)---(选举机制、ZAB协议)

Zookeeper的Leader选举机制

Leader是Zk中最重要的技术之一,也是保证分布式数据一致性的关键所在。

过半性

所谓“过半性”就是指大于集群机器数量的一半,即大于或等于(n/2+1)

首先需要先讲讲服务器启动时期的Leader选举

Leader选举的条件是集群中最少有两台服务器,这里以3台机器为例。
在服务器集群初始化阶段,当有一台服务器(假设这台集群的myid 为1,因此称其为Server1)启动的时候,它是无法进行选举的,当第二台集群(myid 2 | Server2)也启动后,此时这两台机器已经能够互相通信,每台机器都视图找到一个Leader,于是便进入了Leader选举流程。

1、每个Server会发出一个投票
由于是初始情况,因此对于Server1和Server2来说,都会将自己作为Leader来进行投票,每次投票包含的最基本的元素包括:所推举的服务器的myid和ZXID(最大事务ID),我们以(myid,ZXID)的形式来表示。因为是初始化节点,因此都会投给自己,即Server1的投票为(1,0),Server2为(2,0),然后各自将这个投票发给集群中的其他所有机器

2、接收来自各个服务器的投票
集群中的每个服务器在接收到投票后首先会判断该投票的有效性,包括检查是否是本轮投票、是否来自LOOKING状态(寻找Leader状态)的服务器。

3、处理投票
针对每一个偷拍哦。服务器都需要将别人的投票和自己的投票进行PK,PK的规则如下。

  • 优先检查ZXID,ZXID比较大的服务器优先作为Leader
  • 如果ZXID相同的话,那么就比较myid。myid比较大的服务器作为Leader服务器
    上述情景中,Server1发现接收到的投票中的ZXID相同,myid是2,大于自己,于是就会更新自己的投票为(2,0)然后重新将投票发出去,而对于Server来说不需要更新自己的投票信息,只需要再次向集群中的所有机器发出上一次投票信息即可

4、统计投票
每次投票后,服务器都会统计所有投票,判断是否有过半的机器接收到相同的投票信息。对应Server1和Server2服务器来说,都统计出集群中已经有两台机器接受了(2,0)这个投票信息。满足过半性,即认为已经选出了Leader。

5、改变服务器状态
一旦确定了Leader,每个服务器就会更新自己的状态:如果是Follower,则变更为FOLLOWING,如果是Leader,那么就变更为LEADING。

服务器运行期间的Leader选举

在Zookeeper集群正常运行过程中,一旦选出一个Leader,那么所有的服务器 的集群角色都不会再发生变化,也就是说,Leader服务器将一直作为集群的Leader,除非Leader服务器挂掉了,那么整个集群将暂时无法对外提供服务,而是进入新一轮的Leader选举,与服务器启动使其的选举过程是一致的。

假设Server2挂了

1、变更状态
当Leader挂了之后,余下非Observer服务器都会将自己的服务器状态变更为LOOKING,然后开始进入Leader选举过程。

2、每个Server会发出一个投票
由于是运行期间,因此每个服务器上的ZXID可能不同我们假设Server1的ZXID为123,而Server3的ZXID为122,在第一轮投票中,Server1和Server3都会投给自己,即分别产生投票(1,123),(3,122),然后各自将这个投票发给集群中所有机器。

3、接收各个服务器的投票

4、处理投票
对于投票的处理,和上面提到的服务器启动期间的处理规则是一致的,在这个情境下Server1的ZXID为123,Server3的ZXID为122,显然Server1会成为Leader

5、统计投票

6、改变服务器状态

Zookeeper的ZAB协议(一致性协议)

ZAB协议是为分布式协调服务ZK专门设计的一种支持崩溃恢复和原子广播的协议。

在ZK中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,Zookeeper实现了一种主备模式的系统架构来保持集群中各个副本之间数据的一致性。具体的,Zk使用一个单一的主进程来接受并处理客户端的所有事务请求。

**ZAB协议的核心**是定义了对于那些会改变ZK服务器数据状态的事务请求的处理方式,即
所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为leader服务器,而余下的其他
服务器则称为follower服务器,leader服务器负责将一个客户端事务请求转换成一个事务Proposal(提
议),并将该Proposal分发给集群中所有的Follower服务器,之后leader服务器需要等待所有的follower服
务  器的ack,一旦超过半数的follwer服务器进行了正确的反馈之后,那么leader就会再次向所有的follower
服务器分发Commit消息,要求其向前一个Proposal进行提交.

ZAB协议的两种基本的模式:

消息广播
Zookeeper学习(2)---(选举机制、ZAB协议)_第1张图片
ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程。针对客户端的事务请求Leader服务器会为其生成对应的事务Proposal(提议),并将其发送给集群中其余所有的机器,然后在分别收集各自的选票,最后进行事务提交。

在ZAB协议的二阶段提交过程中,溢出了中断逻辑,所有的Follower服务器要么正常反馈Leader提出的事务Proposal,要么就抛弃Leader服务器。同时ZAB协议将二阶段提交中的中断逻辑移除意味着我们可以在过半的Follower服务器已经反馈ACK之后就开始提交事务Proposal了,而不需要等待集群中所有的Follwer服务器都反馈响应。但是,这种简化了的二阶段提交模型下,**是无法处理Leader服务器崩溃退出而带来的数据不一致问题的,**因此在ZAB协议中添加了崩溃恢复模式来解决这个问题。

Zookeeper中消息广播的具体步骤如下:

  1. 客户端发起一个事务操作请求
  2. 如果是Follower服务器接收到请求,则将这个事务请求转发给Leader服务器,Leader服务器将客户端的请求转化为事务Proposal提议,同时为每一个事务Proposal分配一个全局唯一的事务ID(ZXID)
  3. Leader服务器与每个Follower服务器之间都有一个队列,Leader将这个Proposal发送给队列
  4. Follower服务器从队列中取出消息之后写入本地日志,向Leader发送ACK确认。
  5. Leader服务器收到半数以上的Folllower的ACK之后,即认为可以发送Commit消息
  6. Leaer服务器向所有的Follower服务器发送Commit消息
  7. Leader和Follwer服务器会做事务的提交,将服务器内存中的数据做改变。因为客户端是从zk服务器的内存中去获取数据的

特性:Leader服务器与每一个Follwer之间都有一个单独的队列进行消息发送与接收,使用队列消息可以做到异步解耦。Leader和Follower之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞,性能上要下降很多。

整个消息广播协议时基于具有FIFO特性的TCP协议来进行网络通信的,因此能够容易的保证消息广播过程中消息接收与发送的顺序性。

崩溃恢复:当ZAB协议在基于原子广播协议的消息广播过程中,在正常情况下运行非常良好,但是一旦Leader服务器出现崩溃,或者由于网路原因导致Leader服务器是去了与过半Follower服务器的联系,那么就会进入崩溃恢复模式。在ZAB协议中,为了保证程序的正确运行,整个恢复过程结束后需要选举出一个新的Leader服务器。

ZAB协议崩溃恢复要求满足如下2个要求

  1. 确保已经被Leader提交的Proposal必须最终被所有Follower服务器提交
  2. 确保丢弃已经被Leader提出但是还没有被提交的Proposal

根据上述要求,新选举出来的leader不能包含未提交的Proposal,即新选举的leader必须都是已经提交了Proposal的Follower服务器节点,同时,新选举的Leader节点中含有最大事务ID(ZXID),这样做的好处就是可以避免了leader服务器检查Proposal的提交和丢弃工作。

Leader服务器发生崩溃时的如下情景:

  1. leader提出Proposal提议但是并未发出Commit消息之前崩溃,则经过崩溃恢复之后,新选举的leader不一定能是刚才的leader,因为这个Leader存在未提交的proposal。
  2. leader在发送commite消息之后,崩溃。即消息已经发送到队列中。经过崩溃恢复之后,参与选举的follower服务器(刚才崩溃的leader如果恢复运行,则也属于follower节点范畴)中有的节点是消费了队列中所有commit消息,即该follower节点将会被选举为最新的leader。

数据同步过程

当崩溃恢复选举完leader之后就要进行数据同步过程。

  1. 在Zookeeper集群中新的leader选举成功以后,会将自身的最大事务ID(ZXID)发送给集群中的Follower节点。Follower阶段会根据leader的消息进行回退或者是数据同步操作,最终目的要保证集群中所有节点的数据副本保持一致。等到follower服务器将所有其尚未同步的事务Proposal都从Leader服务器上同步过来并成功应用到本地数据库中之后,Leader就会将该Follower服务器加入到真正可用的Follower列表中,并开始之后的其他流程。
  2. ZXID是一个长度64位 的数字,其中低32为可以看做是一个简单的单调递增的计数器,针对客户端的每一个事务请求,leader服务器在产生一个新的事务Proposal的时候,都会对该计数器进行加1的操作;而高32位则代表了leader周期epoch的编号,每当选举产生一个新的leader服务器就会从这个leader服务器上取出其本地日志中最大事务Proposal的ZXID,并从该ZXID中解析出对应的epoch值,然后再对其进行加1操作,之后就会以此编号作为新的epoch,并将低21位置0来开始生成新的ZXID,ZAB协议中的这一通过epoch编号来区分leader周期变化的策略,能够有效的避免不同leader错误的使用相同的ZXID编号提出不一样的事务Proposal的异常情况。

以上ZXID中的epoch也能避免Zookeeper集群中的脑裂,当崩溃恢复之后,可能产生多个leader,follower只会执行epoch最大的leader的Proposal和Commit消息,避免了脑裂产生的问题。

你可能感兴趣的:(Zookeeper)