Zookeeper选举过程与ZAB协议

Zookeeper的选举

选举机制

1. 第一阶段:数据恢复阶段。

每台Zookeeper服务器在启动的时候,都会从本地的数据目录中找到自己所拥有的最大事务id。

2. 第二阶段:选举阶段。

每一个Zookeeper的服务器都会推荐自己当leade并且提交选举协议:

  1. 自己所拥有的最大事务id - Zxid
  2. 自己的选举id - myid
  3. 逻辑时钟值,作用是确保每一台Zookeeper服务器都会处在同一轮选举中
  4. 当前状态
    1 Looking - 选举状态
    1. follower - 追随者
    2. leader - 领导者
    3. observer - 观察者

PK原则

  1. 在选举的时候会先比较两个节点的最大事务id即Zxid。Zxid越大,则说明事务越新。Zxid较大的会胜出
  2. 如果Zxid一致,则比较选举id,选举id较大的胜出。
  3. 满足过半性:即超过一半的节点才能成为leader

过半性

  1. 过半选举:即只有一个节点胜过一半的节点之后才能成为leader
  2. 过半服务:即只有Zookeeper集群中超过一半的节点存活才能对外提供服务
  3. 过半操作:即只有Zookeeper集群中超过一半的节点同意才会提交请求

ZAB协议

Zookeeper的投票和选举的底层是基于了ZAB协议来实现的。ZAB协议是在2PC算法以及Paxos的基础上进行的设计
和延伸。

2PC

sh zkServer.sh status
2PC,是Two-Phase Commit的缩写,即二阶段提交,是计算机网络尤其是在数据库领域内,为了使基于分布式
系统架构下的所有节点在进行事务处理过程中能够保持原子性和一致性而设计的一种算法。通常,二阶段提交协议
也被认为是一种一致性协议,用来保证分布式系统数据的一致性。目前,绝大部分的关系型数据库都是采用二阶段
提交协议来完成分布式事务处理的,利用该协议能够非常方便地完成所有分布式事务参与者的协调,统一决定事务
的提交或回滚,从而能够有效地保证分布式数据一致性,因此二阶段提交协议被广泛地应用在许多分布式系统中。

提交过程

二阶段提交协议是将事务的提交过程分成了两个阶段来进行处理,其执行流程如下。

阶段一:提交事务请求+执行事务
  1. 事务询问。协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的
    响应。
  2. 执行事务。各参与者节点执行事务操作,并将Undo和Redo信息记入事务日志中。
  3. 各参与者向协调者反馈事务询问的响应。如果参与者成功执行了事务操作,那么就反馈给协调者Yes响应,表
    示事务可以执行;如果参与者没有成功执行事务,那么就反馈给协调者No响应,表示事务不可以执行。

由于上面讲述的内容在形式上近似是协调者组织各参与者对一次事务操作的投票表态过程,因此二阶段提交协议的
阶段一也被称为“投票阶段”,即各参与者投票表明是否要继续执行接下去的事务提交操作。

阶段二:事务提交

在阶段二中,协调者会根据各参与者的反馈情况来决定最终是否可以进行事务提交操作,正常情况下,包含以下两
种可能。 执行事务提交 假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务提交。

  1. 发送提交请求。协调者向所有参与者节点发出Commit请求。
  2. 事务提交。参与者接收到Commit请求后,会正式执行事务提交操作,并在完成提交之后释放在整个事务执行
    期间占用的事务资源。
  3. 反馈事务提交结果。参与者在完成事务提交之后,向协调者发送Ack消息。
  4. 完成事务。协调者接收到所有参与者反馈的Ack消息后,完成事务。
    中断事务 假如任何一个参与者向协调者反馈了No响应,或者在等待超时之后,协调者尚无法接收到所有参与者的
    反馈响应,那么就会中断事务。
  5. 发送回滚请求。协调者向所有参与者节点发出Rollback请求。
  6. 事务回滚。参与者接收到Rollback请求后,会利用其在阶段一中记录的Undo信息来执行事务回滚操作,并 在
    完成回滚之后释放在整个事务执行期间占用的资源。
  7. 反馈事务回滚结果。参与者在完成事务回滚之后,向协调者发送Ack消息。
  8. 中断事务。协调者接收到所有参与者反馈的Ack消息后,完成事务中断。

以上就是二阶段提交过程中,前后两个阶段分别进行的处理逻辑。简单地讲,二阶段提交将一个事务的处理过程分
为了投票和执行两个阶段,其核心是对每个事务都采用先尝试后提交的处理方式,因此也可以将二阶段提交看作一
个强一致性的算法,下图分别展示了二阶段提交过程中“事务提交”和“事务中断”两种场景下的交互流程。
Zookeeper选举过程与ZAB协议_第1张图片
Zookeeper选举过程与ZAB协议_第2张图片

优缺点

二阶段提交协议的优点:原理简单,实现方便。
二阶段提交协议的缺点:同步阻塞、单点问题、脑裂、太过保守。

同步阻塞

二阶段提交协议存在的最明显也是最大的一个问题就是同步阻塞,这会极大地限制分布式系统的性能。在二阶段提
交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,也就是说,各个参与者在等待其他参与者响应的过
程中,将无法进行其他任何操作。

单点问题

在上面的讲解过程中,相信读者可以看出,协调者的角色在整个二阶段提交协议中起到了非常重要的作用。一旦协
调者出现问题,那么整个二阶段提交流程将无法运转,更为严重的是,如果协调者是在阶段二中出现问题的话,那
么其他参与者就无法完成事务。

太过保守

如果在协调者指示参与者进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的
响应信息的话,这时协调者只能依靠其自身的超时机制来判断是否需要中断事务,这样的策略显得比较保守。换句
话说,二阶段提交协议没有设计较为完善的容错机,任意一个节点的失败都会导致整个事务的失败。

ZAB协议

概述

ZAB(Zookeeper Atomic Broadcast)协议是为分布式协调服务ZooKeeper专门设计的一种支持崩溃恢复的原子
广播协议,它是一种特别为ZooKeeper设计的崩溃可恢复的原子消息广播算法。这个算法是一种类2PC算法,在2PC
基础上做的改进。

协议介绍

ZAB协议包括两种基本的模式,分别是:

  1. 消息原子广播(保证数据一致性)
  2. 崩溃恢复(解决2pc算法的单点问题)

消息原子广播

在ZooKeeper中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系
统架构来保持集群中各副本之间数据的一致性,实现分布式数据一致性的这一过程称为消息广播(原子广播)。
具体的,ZooKeeper使用一个单一的主进程(Leader服务器)来接收并处理客户端的所有事务请求,并采用ZAB的
原子广播协议,将服务器数据的状态变更以事务Proposal的形式广播到所有的副本进程(Follower或Observer)上
去。即:所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为Leader服务器,而余下的其
他服务器则成为Follower服务器或observer。

Leader服务器负责将一个客户端事务请求转换成一个事务Proposal(提议),并将该Proposal分发给集群中所有
的Follower服务器。之后Leader服务器需要等待所有Follower服务器的反馈,一旦超过半数的服务器(Follower +
Leader服务器)本身进行了正确的反馈后,那么Leader就会再次向所有的Follower服务器分发Commit消息,要求
其进行提交。较比与2PC算法,ZAB引入了过半性思想。

ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程。针对客户端的事务请求,
Leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选
票,最后进行事务提交。

需要明确的是,ZAB协议中涉及的二阶段提交过程则与2PC不同。在ZAB协议的二阶段提交过程中,我们可以在过
半的Follower服务器已经反馈Ack之后就开始提交事务Proposal了,而不需要等待集群中所有的Follower服务器都
反馈响应。

当然,在这种简化了的二阶段提交模型下,是无法处理Leader服务器崩溃退出而带来的数据不一致问题的,因此在
ZAB协议中添加了另一个模式,即采用崩溃恢复模式来解决这个问题。另外,整个消息广播协议是基于具有FIFO特
性的TCP协议来进行网络通信的,因此能够很容易地保证消息广播过程中消息接收与发送的顺序性。
在整个消息广播过程中,Leader服务器会为每个事务请求生成对应的Proposal来进行广播,并且在广播事务
Proposal之前,Leader服务器会首先为这个事务Proposal分配一个全局单调递增的唯一ID,我们称之为事务
ID(即ZXID)。由于ZAB协议需要保证每一个消息严格的因果关系,因此必须将每一个事务Proposal按照其ZXID
的先后顺序来进行排序与处理。

具体的,在消息广播过程中,Leader服务器会为每一个Follower服务器都各自分配一个单独的队列,然后将需要广
播的事务Proposal依次放入这些队列中去,并且根据FIFO策略进行消息发送。每一个Follower服务器在接收到这个
事务Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给Leader服务
器一个Ack响应。当Leader服务器接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的
Follower服务器以通知其进行事务提交,同时Leader自身也会完成对事务的提交,而每一个Follower服务器在接收
到Commit消息后,也会完成对事务的提交。

崩溃恢复

当整个服务框架在启动过程中,或是当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会
进入恢复模式并选举产生新的Leader服务器。

当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协
议就会退出恢复模式。其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器
的数据状态保持一致。

当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个服务框架就可以进入消息广播
模式了。

当一台同样遵守ZAB协议的服务器启动后加入到集群中时,如果此时集群中已经存在一个Leader服务器在负责进行
消息广播,那么新加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,
然后一起参与到消息广播流程中去。

ZooKeeper设计成只允许唯一的一个Leader服务器来进行事务请求的处理。Leader服务器在接收到客户端的事务
请求后,会生成对应的事务提案并发起一轮广播协议;而如果集群中的其他机器接收到客户端的事务请求,那么这
些非Leader服务器会首先将这个事务请求转发给Leader服务器。

当Leader服务器出现崩溃退出或机器重启,亦或是集群中已经不存在过半的服务器与该Leader服务器保持正常通
信时,那么在重新开始新一轮的原子广播事务操作之前,所有进程首先会使用崩溃恢复协议来使彼此达到一个一致
的状态,于是整个ZAB流程就会从消息广播模式进入到崩溃恢复模式。

一个机器要成为新的Leader,必须获得过半进程的支持,同时由于每个进程都有可能会崩溃,因此,在ZAB协议运
行过程中,前后会出现多个Leader,并且每个进程也有可能会多次成为Leader。进入崩溃恢复模式后,只要集群
中存在过半的服务器能够彼此进行正常通信,那么就可以产生一个新的Leader并再次进入消息广播模式。举个例子
来说,一个由3台机器组成的ZAB服务,通常由1个Leader、2个Follower服务器组成。某一个时刻,假如其中一个
Follower服务器挂了,整个ZAB集群是不会中断服务的,这是因为Leader服务器依然能够获得过半机器(包括
Leader自己)的支持。

你可能感兴趣的:(Zookeeper)