zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、master选举、分布式锁和分布式队列等。Zookeeper起初设计是用来解决分布式系统中都会存在单点故障的问题。
1. Zookeeper 介绍
Zookeepr是一个开源代码的分布式协调服务,由知名互联网公司雅虎创建,是Google Chubby的开源实现。Zookeeper的设计目标时将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可用的原语集。
zookeeper本身支持单机部署和集群部署,生产环境建议使用集群部署,因为集群部署不存在单点故障问题,并且zookeeper建议部署的节点个数为奇数个,只有超过一半的机器不可用整个zk集群才不可用。zookeeper集群中主要有两个角色leader和flower,每个客户端可以连接集群中的任何一个zookeeper节点,同时从其上面read信息。
1.1 Zookeeper分布式一致性要求
- 1、顺序一致性:从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到Zookeeper中;
- 2、原子性:所有事务的请求结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么在整个集群中所有机器上都成功应用了某一个事务,要么都没有应用,没有中间状态;
- 3、单一视图:无论客户端连接的是哪个Zookeeper服务器,其看到的服务端数据模型都是一致的。
- 4、可靠性:一旦服务端成功应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来,除非有另一个事务又对其进行了变更。
- 5、实时性:Zookeeper仅仅保证在一定的时间内,客户端最终一定能够从服务端上读到最终的数据状态。
这个时候我们可能会提出这样的疑问:既然Zookeeper当机器中有多于一半的机器返回正确的反馈之后,Zookeeper Leader机器在向集群中所有的Follower集群提交提案。由于网络延迟和网络分区的原因,数据同步可能出现延迟,那么Zookeeper如何保证数据的单一视图和原子性?
Zookeeper针对write操作,flower节点会转发给leader,由leader负责原子广播,从而保证集群中各个节点的数据一致性,zookeeper中规定只有当多余一半的节点同步完成整个write操作才算完成。也就是说可能会有少于一半的数据不是新数据,因此zookeeper中不是强一致性而是实现的最终一致性。但是客户端可以使用sync来强制读取最新的数据
1.2 Zookeepr的设计目标
简单的数据模型
Zookeeper使得分布式程序额能够通过一个共享的、树形结构的名字空间来进行相互协调,这里所说的树形结构的名字,是指的Zookeeper服务器内存的一个数据模型,其由一系列可以称为ZNode的数据节点组成。总的来说,数据模型类似与一个文件系统,而Znode之间是层级关系;就像文件系统的目录结构一样。
可以构建集群
组成Zookeeper集群的每台机器都会在内存中维护当前的服务器状态,并且每台机器之家你都会相互通信。值得一提的是,只要集群中有超过一半的机器能够正常工作,那么整个集群都能正常对外进行服务。
Zookeeper的客户端会选择和集群中任何一台机器来共同创建一个TCP连接,而且客户端和某台Zookeeper服务之间的连接断开之后,客户端会自动连接到集群中的其他机器。
顺序访问
对于来自客户端的每个更新请求,Zookeeper都会分配一个全局唯一的递增编号(ZKID),这个编号反映了所有事务操作的先后顺序。
高性能
Zookeeper将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,因此它尤其适用于以读操作为主的应用场景。
1.3 Zookeeper 基本概念
集群角色
最典型的集群就是Master/Slave模式(主备模式),此情况下把所有能够处理写操作的机器称为Master机器,把所有通过异步复制方式获取最新数据,并提供读服务的机器为Slave机器。Zookeeper引入了Leader、Follower、Observer三种角色,Zookeeper集群中的所有机器通过Leaser选举过程来选定一台被称为Leader的机器,Leader服务器为客户端提供写服务,Follower和Observer提供读服务,但是Observer不参与Leader选举过程,不参与写操作的"过半写成功"策略,Observer可以在不影响写性能的情况下提升集群的性能。
- leader:
是整个集群工作机制中的核心,其主要工作有:
- 事务请求的唯一调度和处理者,保证集群事务处理的顺序性。
- 集群内部各服务器的调度者。
- follower:
是zookeeper集群状态的跟随者,其主要工作是:
- 处理客户端的非事务请求,转发事务请求给leader服务器。
- 参与事务请求proposal的投票
- 参与leader选举投票
- observer
和follower唯一的区别在于,observer服务器只提供非事务服务,不参与任何形式的投票,包括事务请求proposal的投票和leader选举投票。通常在不影响集群事务处理能力的前提下提升集群的非事务处理能力。
会话
指客户端会话,一个客户端连接是指客户端和服务端之间的一个TCP长连接,Zookeeper对外的服务端口默认为2181,客户端启动的时候,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够心跳检测与服务器保持有效的会话,也能够向Zookeeper服务器发送请求并接受响应,同时还能够通过该连接接受来自服务器的Watch事件通知。
客户端和集群服务器之间会保证心跳连接,也就是说客户端和服务器直接按都有各自的会话租期。
集群服务器在接收到客户端的KeepAlive请求时,首先会将该请求阻塞住,并等到该客户端的当前会话租期即将过期时,才为其续租该客户端的会话租期,之后再向客户端响应这个KeepAlive请求,并同时将最新的会话租期超时时间反馈给客户端。
客户但在接收到来自集群服务器的续租响应后,会立即发起一个新的KeepAlive请求,再由集群服务器行阻塞。因此我们可以看出,在正常运行过程中,每一个Zookeeper客户端总是会有一个KeepAlive请求阻塞在集群服务器上。
数据节点
第一类指构成集群的机器,称为机器节点,第二类是指数据模型中的数据单元,称为数据节点-Znode,Zookeeper将所有数据存储在内存中,数据模型是一棵树,由斜杠/进行分割的路径,就是一个ZNode,如/foo/path1,每个ZNode都会保存自己的数据内存,同时还会保存一些列属性信息。ZNode分为持久节点和临时节点两类,持久节点是指一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上,而临时节点的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。另外,Zookeeper还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,Zookeeper会自动在其节点后面追加一个整形数字,其是由父节点维护的自增数字。
版本
对于每个ZNode,Zookeeper都会为其维护一个叫作Stat的数据结构,Stat记录了这个ZNode的三个数据版本,分别是version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)、aversion(当前ZNode的ACL版本)。
Watcher
Zookeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,Zookeeper服务端会将事件通知到感兴趣的客户端。使用了Java设计模式中的观察者设计模式。
ACL
Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,其定义了如下五种权限:
- CREATE:创建子节点的权限。
- READ:获取节点数据和子节点列表的权限。
- WRITE:更新节点数据的权限。
- DELETE:删除子节点的权限。
- ADMIN:设置节点ACL的权限。
2. Zookeeper ZAB协议
Zookeeper为分布式应用提供高效且可靠的分布式协调服务,提供了统一命名服务、配置管理、分布式锁等分布式的基础服务。Zookeeper并没有直接采用Paxos算法,而是采用了一种被称为** ZAB(Zookeeper Atomic Broadcast) ** 的一致性协议。
Zookeeper使用了Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法。ZAB协议是为Zookeeper专门设计的一种__支持崩溃恢复的原子广播协议。
2.1 ZAB协议
所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为leader服务器,而余下的其他服务器则成为follower服务器。leader服务器负责将一个客户端事务请求转换成一个事务proposal,并将该proposal分发给集群中所有的follower服务器。之后leader服务器需要等待所有follower服务器的反馈,一旦超过半数的follower服务器进行了正确的反馈后,那么leader就会再次向所有的follower服务器分发commit消息,要求其将前一个proposal进行提交。
在Zookeeper中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,Zookeeper实现了一种主备模式的系统架构来保证集群中副本之间的数据一致性。具体的,Zookeeper使用了一个单一的主进程来接受并处理客户端的所有事务请求,并且使用一种ZAB原子广播协议,将服务器数据的状态变更以事务Proposal的形式广播到所有副本上面去。
ZAB协议需要确保那些已经在leader服务器上提交的事务最终被所有服务器都提交。ZAB协议需要确保丢弃那些只在leader服务器上被提出的事务。如果让leader选举算法能够保证新选举出来的leader服务器拥有集群中所有机器最高编号(ZXID)的事务proposal,那么就可以保证这个新选举出来的leader一定具有所有已经提交的提案。
2.2 ZAB两种基本的模式:崩溃恢复和消息广播
消息广播
ZAB协议的消息广播过程使用原子广播协议,类似于一个二阶段提交过程,针对客户端的事务请求,Leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交。
整个消息广播协议是基于具有FIFO特性的TCP协议来进行网络通信的,因此能够很容易保证消息广播过程中消息接受与发送的顺序性。
整个消息广播过程中,Leader服务器会为每个事务请求生成对应的Proposal来进行广播,并且在广播事务Proposal之前,Leader服务器会首先为这个事务Proposal分配一个全局单调递增的唯一ID,称之为事务ID(ZXID),由于ZAB协议需要保证每个消息严格的因果关系,因此必须将每个事务Proposal按照其ZXID的先后顺序来进行排序和处理。每一个Follower服务器在接受到这个事务Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且成功写入之后反馈给Leader服务器ACK响应。当Leader服务器接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的Follower服务器以通知其进行事务提交,同时Leader自身也对事务进行提交,而每一个Follower服务器在接受到Commit请求消息之后,也会完成对事务的提交。
当一台同样遵守ZAB协议的服务器启动后加入到集群中,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
崩溃恢复
当整个服务框架启动过程中或Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader服务器。
当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式,那么整个服务框架就可以进入消息广播模式。
Leader选举算法不仅仅需要让Leader自身知道已经被选举为Leader,同时还需要让集群中的所有其他机器也能够快速地感知到选举产生的新的Leader服务器。
当Leader服务器出现崩溃或者机器重启、集群中已经不存在过半的服务器与Leader服务器保持正常通信时,那么在重新开始新的一轮的原子广播事务操作之前,所有进程首先会使用崩溃恢复协议来使彼此到达一致状态,于是整个ZAB流程就会从消息广播模式进入到崩溃恢复模式。
基本特性
ZAB协议规定了如果一个事务Proposal在一台机器上被处理成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障崩溃
ZAB协议规定在崩溃恢复过程中必须要满足以下两个条件:
- ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交。即使由于Leader服务器崩溃之后,造成Commit提交请求没有发送给所有的Follower服务器。
- ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务
如果在崩溃恢复过程中出现一个需要被丢弃的提议,那么在崩溃恢复结束后需要跳过该事务Proposal。在崩溃恢复过程中需要处理的特殊情况,就决定了ZAB协议必须设计这样的。
结合上面规定的两个条件,就决定了ZAB协议必须设计这样的一个Ledaer选举算法:能够确保提交已经被Leader提交的事务的Proposal,同时丢弃已经被跳过的事务Proposal。如果让Leader选举算法能够保证新选举出来的Leader服务器拥有集群中所有机器最高编号(ZXID最大)的事务Proposal,那么就可以保证这个新选举出来的Leader一定具有所有已经提交的提议,更为重要的是如果让具有最高编号事务的Proposal机器称为Leader,就可以省去Leader服务器查询Proposal的提交和丢弃工作这一步骤了
数据同步
完成Leader选举后,在正式开始工作前,Leader服务器首先会确认日志中的所有Proposal是否都已经被集群中的过半机器提交了,即是否完成了数据同步。
Leader服务器需要确保所有的Follower服务器能够接受到每一条事务Proposal,并且能够将所有已经提交的事务Proposal应用到内存数据库中去。具体的,Leader服务器回味每一个Follower服务器准备一个队列,并将那些没有被Follower服务器同步的事务以Proposal消息的形式逐个发送到Follower服务器中,并且每一个Proposal消息后面紧跟一个Commit消息,以表示该事务已经被提交。
下面分析ZAB协议如何处理需要丢弃的事务Proposal的,ZXID是一个64位的数字,其中低32位可以看做是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal时,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举产生一个新的Leader时,就会从这个Leader上取出其本地日志中最大事务Proposal的ZXID,并解析出epoch['ɛpək]值,然后加1,之后以该编号作为新的epoch,低32位从0来开始生成新的ZXID,ZAB协议通过epoch号来区分Leader周期变化的策略,能够有效地避免不同的Leader服务器错误地使用不同的ZXID编号提出不一样的事务Proposal的异常情况。当一个包含了上一个Leader周期中尚未提交过的事务Proposal的服务器启动时,其肯定无法成为Leader,因为当前集群中一定包含了一个Quorum(过半)集合,该集合中的机器一定包含了更高epoch的事务的Proposal,因此这台机器的事务Proposal并非最高,也就无法成为Leader。
当这台机器加入集群中,Follower角色连接到Leader服务器之后,Leader服务器会根据自己服务上最后被提交的Proposal和Follower服务器的Proposal机械能对比,对比结果就是当然Leader服务器会要求Follow进行一个回退操作————回退到一个确实已经被集群中过半机器提交的最新事务Proposal。
3. ZAB协议原理
ZAB主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是发现(Discovery)、同步(Synchronization)、广播(Broadcast)阶段。ZAB的每一个分布式进程会循环执行这三个阶段,称为主进程周期。
- 发现,选举产生PL(prospective leader),PL收集Follower epoch(cepoch),根据Follower的反馈,PL产生newepoch(每次选举产生新Leader的同时产生新epoch)。
- 同步,PL补齐相比Follower多数派缺失的状态、之后各Follower再补齐相比PL缺失的状态,PL和Follower完成状态同步后PL变为正式Leader(established leader)。
- 广播,Leader处理客户端的写操作,并将状态变更广播至Follower,Follower多数派通过之后Leader发起将状态变更落地(deliver/commit)。
在正常运行过程中,ZAB协议会一直运行于阶段三来反复进行消息广播流程,如果出现崩溃或其他原因导致Leader缺失,那么此时ZAB协议会再次进入发现阶段,选举新的Leader。
每个进程都有可能处于如下三种状态之一
- LOOKING:Leader选举阶段。
- FOLLOWING:Follower服务器和Leader服务器保持同步状态。
- LEADING:Leader服务器作为主进程领导状态。
一个Follower只能和一个Leader保持同步,Leader进程和所有与所有的Follower进程之间都通过心跳检测机制来感知彼此的情况。若Leader能够在超时时间内正常收到心跳检测,那么Follower就会一直与该Leader保持连接,而如果在指定时间内Leader无法从过半的Follower进程那里接收到心跳检测,或者TCP连接断开,那么Leader会放弃当前周期的领导,转换到LOOKING状态。
3.1 ZAB与Paxos的联系和区别
联系:
- 都存在一个类似于Leader进程的角色,由其负责协调多个Follower进程的运行。
- Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提议进行提交。
- 在ZAB协议中,每个Proposal中都包含了一个epoch值,用来代表当前的Leader周期,在Paxos算法中,同样存在这样的一个标识,名字为Ballot。
区别:
- Paxos算法中,新选举产生的主进程会进行两个阶段的工作,第一阶段称为读阶段,新的主进程和其他进程通信来收集主进程提出的提议,并将它们提交。第二阶段称为写阶段,当前主进程开始提出自己的提议。
- ZAB协议在Paxos基础上添加了同步阶段,此时,新的Leader会确保存在过半的Follower已经提交了之前的Leader周期中的所有事务Proposal。
- ZAB协议主要用于构建一个高可用的分布式数据主备系统,而Paxos算法则用于构建一个分布式的一致性状态机系统。
4. 为什么Zookeeper中需要搭建奇数台服务器
1. 容错
由于在增删改操作中需要半数以上服务器通过,来分析以下情况。
2台服务器,至少2台正常运行才行(2的半数为1,半数以上最少为2),正常运行1台服务器都不允许挂掉
3台服务器,至少2台正常运行才行(3的半数为1.5,半数以上最少为2),正常运行可以允许1台服务器挂掉
4台服务器,至少3台正常运行才行(4的半数为2,半数以上最少为3),正常运行可以允许1台服务器挂掉
5台服务器,至少3台正常运行才行(5的半数为2.5,半数以上最少为3),正常运行可以允许2台服务器挂掉
6台服务器,至少3台正常运行才行(6的半数为3,半数以上最少为4),正常运行可以允许2台服务器挂掉
通过以上可以发现,3台服务器和4台服务器都最多允许1台服务器挂掉,5台服务器和6台服务器都最多允许2台服务器挂掉
但是明显4台服务器成本高于3台服务器成本,6台服务器成本高于5服务器成本。这是由于半数以上投票通过决定的。
2. 防脑裂
一个zookeeper集群中,可以有多个follower、observer服务器,但是必需只能有一个leader服务器。
如果leader服务器挂掉了,剩下的服务器集群会通过半数以上投票选出一个新的leader服务器。
集群互不通讯情况:
一个集群3台服务器,全部运行正常,但是其中1台裂开了,和另外2台无法通讯。3台机器里面2台正常运行过半票可以选出一个leader。
一个集群4台服务器,全部运行正常,但是其中2台裂开了,和另外2台无法通讯。4台机器里面2台正常工作没有过半票以上达到3,无法选出leader正常运行。
一个集群5台服务器,全部运行正常,但是其中2台裂开了,和另外3台无法通讯。5台机器里面3台正常运行过半票可以选出一个leader。
一个集群6台服务器,全部运行正常,但是其中3台裂开了,和另外3台无法通讯。6台机器里面3台正常工作没有过半票以上达到4,无法选出leader正常运行。
通可以上分析可以看出,为什么zookeeper集群数量总是单出现,主要原因还是在于第2点,防脑裂,对于第1点,无非是正本控制,但是不影响集群正常运行。但是出现第2种裂的情况,zookeeper集群就无法正常运行了。
4. Zookeeper中的Leader选举算法
4.1 重要概念
- SID:服务器ID,用SID来唯一标识Zookeeper集群中的机器,每台机器都不能重复,和myid的值一致。
- ZXID:事务ID,ZXID是一个事务ID,用来唯一标识一次服务器状态的变更。在某一个时刻,集群中每台机器的ZXID指不一定都一致。ZXID由2部分组成zxid是 64 位,高 32 位是 epoch。编号低32 位是counter消息计数器;
epoch:可以理解为当前集群所处的年代或者周期,每个leader 就像皇帝,都有自己的年号,所以每次改朝换代,leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为follower 只听从当前年代的 leader 的命令。
counter消息计数器: 其中低32位可以看做是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal时,都会对该计数器进行加1操作,对事务请求唯一标识。
4.2 Leader选举
Zookeeper中的Leader选举分为两个过程:
- 启动时候的Leader选举
- Leader崩溃恢复时候的Leader选举
4.2.1 服务器启动时的 leader 选举
每个节点启动的时候状态都是 LOOKING,处于观望状态,接下来就开始进行选主流程
进行 Leader 选举,至少需要两台机器(具体原因前面已经讲过了),我们选取 3 台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器 Server1 启动时,它本身是无法进行和完成 Leader 选举,当第二台服务器 Server2 启动时,这个时候两台机器可以相互通信,每台机器都试图找到 Leader,于是进入 Leader 选举过程。选举过程如下:
- 每个 Server 发出一个投票。由于是初始情况,Server1和 Server2都会将自己作为 Leader 服务器来进行投票,每次投票会包含所推举的服务器的 myid 和 ZXID、epoch,使用(myid, ZXID,epoch)来表示,此时 Server1的投票为(1, 1, 0),Server2 的投票为(2, 2, 0),然后每个Follower服务器,各自将这个投票发给集群中其他机器。
- 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自LOOKING状态的服务器。
- 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行 PK,PK 规则如下
- 优先检查 ZXID。ZXID 比较大的服务器优先作为Leader。如果 leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(ZXID 最大)的事务Proposal,那么就可以保证这个新选举出来的 Leader 一定具有已经提交的提案。因为所有提案被 COMMIT 之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 COMMIT 消息的 proposal 状态
- 如果 ZXID 相同,那么就比较 myid。myid 较大的服务器作为 Leader 服务器。
对于 Server1 而言,它的投票是(1, 0, 0),接收 Server2的投票为(2, 0, 0),首先会比较两者的 ZXID,均为 0,再比较 myid,此时 Server2 的 myid 最大,于是更新自己的投票为(2, 0),然后重新投票,对于 Server2 而言,它不需要更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
- 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于 Server1、Server2 而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了 Leader。
- 改变服务器状态。一旦确定了 Leader,每个服务器就会更新自己的状态,如果是 Follower,那么就变更为FOLLOWING,如果是 Leader,就变更为 LEADING。
4.2.2 运行过程中的 leader 选举
运行过程中的 leader 选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。
-
变更状态。Leader 挂后,余下的非 Observer 服务器都会将自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
-
每个 Server 会发出一个投票。在运行期间,每个服务器上的 ZXID 可能不同,此时假定 Server1 的 ZXID 为123,Server3的ZXID为122;在第一轮投票中,Server1和 Server3 都会投自己,产生投票(1, 123, 0),(3, 122, 0),然后各自将投票发送给集群中所有机器。接收来自各个服务器的投票。与启动时过程相同。
-
处理投票。与启动时过程相同。Server1不需要更新自己的投票,Server1最后投票结果是(1, 123 , 0)。由于Server1的ZXID比Server2的ZXID高,所以更新Server2的投票结果(2, 123 , 0).
-
统计投票。与启动时过程相同。每台服务器统计所有集群的投票信息,判断是否有超过一半的机器具有相同的投票信息。对于Server1和Server2来说,它们具有相同的投票信息,并且超过原有机器的一般。所有接受投票过程,选举出Leader机器。
-
改变服务器的状态。与启动时过程相同,然后同步Leader服务器状态。