Apache Zookeeper 是由Apache Hadoop 的子项目发展而来。Zookeeper 为分布式应用提供了高效且可靠的分布式协调服务,提供了诸如统一命名服务,配置管理和分布式锁等分布式的基础服务。在解决分布式数据一致性方面,Zookeeper 并没有直接采用 Paxos 算法,而是用了 ZAB(Zookeeper Atomic Broadcast)的一致性算法。1.初识 Zookeeper1.Zookeeper 介绍Zookeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。Zookeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单的接口提供给用户使用。Zookeeper 是什么Zookeeper 是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/订阅,负载均衡,命名服务,分布式协调/通知,集群管理,Master选举,分布式锁和分布式队列等功能。Zookeeper 可以保证如下分布式一致性特性:1.顺序一致性从同一个客户端发起的事务请求,最终将会严格的按照其发起顺序被应用到 Zookeeper 中去。2.原子性所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群所有机器都成功应用了某一个事务,要么都没有应用,一定不会出现集群中部分机器应用了事务,而另外一部分没有应用。3.单一视图无论客户端连接的是哪个Zookeeper服务器,其看到的服务端的数据模型都是一致的。4.可靠性一旦服务端成功应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更会一直保留下来,除非有另外一个事务又对其进行了变更。5.实时性通常人们看到实时性的反应是,一旦一个事务被成功应用,那么客户端能立即从服务端上读取到这个事务的最新数据状态。这里需要注意的是,Zookeeper 仅仅保证在一定时间内,客户端最终一定能够从服务端上读取到最新的数据状态。Zookeeper 设计目标Zookeeper 致力于提供一个高性能,高可用,具有严格的顺序访问控制能力(主要是写操作的严格顺序性)的分布式协调服务。高性能使得Zookeeper能够应用于那些对系统吞吐有明确要求的大型分布式系统中,高可用使得分布式单点问题得到了很好的解决,而严格的顺序访问能力使得客户端能够基于Zookeeper 实现一些复杂的同步原语。目标一:简单的数据模型Zookeeper 使得分布式程序能够通过一个共享的,树形结构的名字空间来进行互相协调。这里说的树形结构的名字空间,是指Zookeeper 服务器内存中的一个数据模型,其由一系列被称为ZNode的数据节点组成,总的来说,其数据模型类似于一个文件系统,而ZNode之间的层级关系,就像文件系统的目录结构一样。不过和传统的磁盘文件系统不同,Zookeeper将全量数据存储在内存中,以此来实现提高服务器吞吐,减少延迟的目的。目标二:可以构建集群一个Zookeeper集群通常是由一组机器组成,一般3~5台机器就可以组成一个可用的Zookeeper 集群了。组成Zookeeper集群的每台机器都会在内存中维护当前的服务器状态,并且每台机器之间都互相保持着通信。值得一提的是,只要集群中存在超过一半的机器能够正常工作,那么整个集群就能够对外提供服务。Zookeeper的客户端程序会选择和集群中任意一台机器共同来创建一个tcp连接,而一旦客户端和某台Zookeeper服务器之间的连接断开之后,客户端会自动连接到集群中的其他机器。目标三:顺序访问对于来自客户端的每个更新请求,Zookeeper 都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序,应用程序可以使用Zookeeper的这个特性来实现更高层次的同步原语。目标四:高性能由于 Zookeeper 将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,因此它尤其适用于以读操作为主的应用场景。3.Zookeeper 的基本概念   集群角色通常在分布式系统中,构成一个集群的每一台机器都有自己的角色,最典型的集群模式就是 Master/Slave 模式(主备模式)。在这种模式中,我们把能够处理所有写操作的机器称为 Master 机器,把所有通过异步复制方式获取最新数据,并提供读操作的机器称为 Slave 机器。而在 Zookeeper 中,它没有沿用 Master/Slave 概念,而是引入了 Leader,Follower,和 Observer 三种角色。Zookeeper 集群中的所有机器都通过一个 Leader 选举过程来选定一台被称为 "Leader" 的机器,Leader 服务器为客户端提供读和写服务。除Leader外,其他机器包括Follower和Observer。Follower和Observer都能提供读服务,唯一的区别在于 Observer 机器不参与 Leader 选举过程,也不参与写操作的 '过半写成功' 策略,因此 Observer可以在不影响写性能的情况下提升集群的读性能。会话(session)session 是指客户端会话。在 Zookeeper 中,一个客户端连接是指客户端和服务端之间的一个tcp连接。Zookeeper 对外的服务端默认端口是 2181,客户端启动的时候,首先会与服务器建立一个tcp连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过心跳检测与服务端保持有效的会话。也能够向 Zookeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务端的 Watch 事件通知。Session 的 sessionTimeout 值用来设置一个客户端会话的超时时间。由于服务器压力大,网络故障或客户端主动断开连接等各种原因导致客户端连接断开时,只要在 sessionTimeout 规定的时间内能够重新连接上集群的任一一台服务器,那么之前创建的会话仍然有效。数据节点(Znode)在谈到分布式的时候,我们通常说的'节点'是指组成集群中的每一台机器。然后,在 Zookeeper 中,'节点'分为两类:第一类同样是指构成集群的机器,我们称之为'机器节点';第二类是指数据模型中的数据单元,我们称之为数据节点---ZNode。Zookeeper 将所有的数据存储在内存中,数据模型是一个树(ZNode Tree),由斜杆(/)进行分割的路径,就是一个ZNode,例如 /foo/path1。每个 ZNode 上都会保存自己的数据内容,同时还会保存一系列属性信息。在 Zookeeper 中,ZNode 可以分为持久节点 和临时节点。所谓持久节点是指一旦这个 ZNode 被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在 Zookeeper 上。而临时节点就不一样了,它的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。另外,Zookeeper 还允许用户为每一个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,Zookeeper 会自动在其节点名后面追加一个整型数字,这个整型数字是一个由父节点维护的自增数字。版本Zookeeper 每个Znode 上都会存储数据,对应于每个ZNode,Zookeeper 都会为其维护一个叫做 Stat 的数据结构,Stat中记录了这个 ZNode 的三个数据版本。分别是 version(当前 ZNode 的版本),cversion(当前 ZNode 子节点的版本),和 aversion(当前 ZNode 的 ACL 版本)。WatcherWatcher(事件监听器),是 Zookeeper 中的一个很重要的特性。Zookeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,Zookeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 Zookeeper 实现分布式协调服务的重要特性。ACLZookeeper 采用 ACL(Access Control Lists) 策略来进行权限控制。1.CREATE:创建子节点的权限2.READ:获取节点数据和子节点列表的权限3.WRITE:更新节点数据的权限4.DELETE:删除子节点的权限5.ADMIN:设置节点ACL的权限需要注意的是,CREATE和DELETE 这2个都是针对子节点的权限控制。2.Zookeeper 的 ZAB 协议1.ZAB 协议Zookeeper 并没有完全采用 Paxos 算法,而是使用了一种称为 Zookeeper Atomic Broadcast(ZAB,Zookeeper 原子消息广播协议)的协议作为其数据一致性的核心算法。ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 Zookeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,Zookeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间数据的一致性。具体的,Zookeeper 使用了单一的主进程来接收并处理客户端的所有请求事务,并采用 ZAB 的原子广播协议,将服务器数据的状态变更以事务的Proposal 的形式广播到所有的副本进程上去。ZAB 协议的这个主备模型架构保持了同一时刻集群中只能有一个主进程来广播服务器的状态变更,因此能够很好地 处理客户端大量的并发请求。另一方面,考虑到分布式环境中,顺序执行的一些状态变更其前后具有一定的依赖关系,有些状态的变更必须依赖于比它早生成的那些状态变更。这样的依赖关系也对ZAB提出了一个要求:ZAB协议必须能够保证一个全局的变更序列被顺序的应用,也就是说,ZAB 协议需要保证如果一个状态变更已经被处理了,那么所有其依赖的状态变更都应该已经被提前处理了。最后,考虑到主进程在任何时候都有可能出现崩溃,因此,zab 协议还需要做到当前主进程出现上述异常的时候,仍能正常工作。zab 协议的核心是定义了对于那些会改变 Zookeeper 服务器数据状态的事务请求的处理方式,即:所有的事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 Leader 服务器,而余下的服务器则称为 Follower 服务器。Leader服务器负责将一个客户端事务请求转换成一个事务Proposal(提议),并将该 Proposal 分发给集群中所有的 Follower 服务器。之后 Leader 服务器需要等待所有Follower 服务器的反馈,一旦超过半数的 Follower 服务器进行了正确的反馈后,那么 Leader 就会再次向所有的 Follower 服务器分发 Commit 消息,要求其将前一个 Proposal 进行提交。2.协议介绍zab 协议包括两种基本的模式:崩溃恢复和消息广播。当整个服务框架在启动过程中,或是当 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并再次进入消息广播模式。消息广播:zab 协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程。针对客户端的事务请求,leader 服务器会为其生成对应的事务 Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交。zab 协议中涉及的二阶段提交过程略有不同。在 zab 协议的二阶段提交过程中,移除了中断逻辑,所有的follower服务器要么正常反馈leader提出的事务Proposal,要么就抛弃leader服务器。同时,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响应后,同时 leader 自身也会完成对事务的提交,而每一个 follower 服务器在接收到 commit 消息后,也会完成对事务的提交。崩溃恢复:zab 协议的这个基于原子广播协议的消息广播过程,在正常情况下运行非常良好,但是一旦leader服务器出现崩溃,或者是由于网络原因导致leader服务器失去了与过半 follower 的联系,那么就会进入崩溃恢复模式。在 zab 协议中,为了保证程序的正确运行,整个恢复过程结束后需要选举出一个新的leader服务器。因此,zab 协议需要一个高效且可靠的 leader 选举算法,从而确保能够快速的选举出现的 leader,同时,leader 选举算法不仅需要让 leader自己知道其自身已经被选举为 leader,同时还要让集群中的所有其他机器也能够快速的感知到选举产生新的leader服务器。基本特性:zab 协议规定了如果一个事务Proposal在一台机器上被处理成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障。1.zab 协议需要确保哪些已经在 leader 服务器上提交的事务最终被所有服务器都提交。2.zab 协议需要确保丢弃那些只在 leader 服务器上被提出的事务相反,如果在崩溃恢复过程中出现一个需要被丢弃的提案,那么在崩溃恢复结束后需要跳过该事务Proposal。结合上面的情况,就决定了 zab 协议必须设计这样一个 leader 选举算法:能够确保提交已经被 leader 提交的事务Proposal,同时丢弃已经被跳过的事务 Proposal。针对这个要求,如果让 leader选举算法能够保证新选举出来的 leader 服务器拥有集群中所有机器最高编号(即 ZXID 最大)的事务Proposal,那么就可以保证这个新选举出来的 leader 一定具有所有已经提交的提案。更为重要的是,如果让具有最高编号事务 Proposal 的机器称为 leader,就可以省去Leader服务器检查 Proposal 的提交和丢弃工作这一步操作了。数据同步:完成leader选举之后,在正式开始工作(即接收客户端的事务请求,然后提出新的提案)之前,leader 服务器会首先确认事务日志中的所有Proposal是否都已经被集群中过半的机器提交了,即是否完成数据同步。所有正常运行的服务器,要么成为leader,要么成为follower并和 leader 保持同步。leader 服务器需要确保所有的follower服务器能够接受到每一条事务Proposal,并且能够正确的将所有已经提交的事务Proposal应用到内存数据库中去。具体的,leader服务器会为每一个follower服务器都准备一个队列,并将那些没有被各follower服务器同步的事务以 Proposal 消息的形式逐个发送到follower服务器,并且在每一个 Proposal 消息后面紧接着再发送一个commit 消息,以表示该事务已经被提交。等到follower服务器将所有尚未同步的事务 Proposal 都从 leader 服务器上同步过来并成功应用到本地数据库中后,leader 服务器就会将该 follower 服务器加入到期真正可用的 follower 列表中,并开始之后的流程。zab 协议是如何处理那些需要丢弃的事务 Proposal的。在 zab 协议的事务编号 ZXID 设计中,ZXID 是一个64位的数字,其中低32位可以看做是一个简单的单调递增的计数器,针对客户端的每一个事务请求,leader服务器在产生一个新的事务Proposal的时候,都会针对该计数器进行加1操作;而高32位则代表了leader 周期 epoch 的编号,每当选举一个新的leader服务器,就会从这个leader服务器上去除其本地日志中最大事务Proposal 的 ZXID,并从该ZXID中解析出对应的 epoch 值,然后再对其加1操作,之后就会以该编号作为新的 epoch,并将低32位置0来开始生成新的 ZXID。zab 协议中的这一通过epoch 编号来区分 leader 周期变化的策略,能够有效的避免不同的 leader 服务器错误的使用相同的 ZXID 编号提出不一样的事务 Proposal的异常情况,这对于识别在 leader 崩溃恢复前后生成的 Proposal 非常有帮助,大大简化和提升了数据恢复的流程。基于这样的策略,当一个包含了上一个leader周期中尚未提交的事务 Proposal 的服务器启动时,其肯定无法成为 leader,原因很简单,因为当前集群中一定包含一个 Quorum 集合,该集合中的机器一定包含了更高的 epoch 的事务 Proposal,因此这台机器的事务 Proposal 肯定不是最高的,也就无法成为 leader了。当这台机器加入到集群中,以 follower 角色连接上leader服务器之后,leader服务器会根据自己服务器上最后被提交的Proposal来和 follower服务器的Proposal 进行对比,对比的结果当然是 leader会要求 follower 进行一个回退操作---回退到一个确实已经被集群中过半集群提交的最新的事务 Proposal.3.深入ZAB协议1.系统模型通常在由一组进程 {P1,P2,...Pn} 组成的分布式系统中,其中每一个进程都具有各自的存储设备,各进程之间通过互相通信来实现消息的传递。一般的,在这样的一个分布式系统中,每一个进程都随时有可能会出现一次或多次的崩溃退出,当然,这些进程会在恢复之后再次加入到进程组中。如果一个进程正常工作,那么我们称该进程处于 UP 状态,如果一个进程崩溃了,那么我们称其为 DOWN状态。事实上,当集群中存在过半处于 UP 状态的进程组成的一个进程子集之后,就可以进行正常的消息广播了。我们将这样一个进程子集称为 Quorum。我们使用 Pi和Pj 来分别表示进程组中的两个不同进程,使用Cij 来表示进程 Pi 和 Pj 之间的网络通信信道,其基本满足两个基本特征:1.完整性(Integrity)进程 Pj 如果收到了来自进程 Pi 的消息m,那么进程 Pi 一定确实发送了消息m。2.前置性(Prefix)如果进程 Pj 收到了消息m,那么存在这样的消息m1:如果消息m1是消息m的前置消息,那么Pj 务必先接收到消息m1,然后再接收到消息m。我们将存在这种前置性关系的两个消息表示为:m1<m。前置性是整个消息协议设计中最关键的一点,由于每一个消息都有可能是基于之前的消息进行的,因此所有的消息都必须按照严格的先后顺序进行处理。2.问题描述Zookeeper 是一个高可用的分布式协调服务,在很多大型系统上得到应用。这类应用有一个共同的特点,即通常都存在大量的客户端进程,并且都依赖 Zookeeper 来完成一系列诸如可靠的配置存储和运行时状态记录等分布式协作工作。鉴于这些大型应用对 Zookeeper 的依赖,因此 Zookeeper 必须具备高吞吐和低延迟的特性,并且能够很好的在高并发情况下完成分布式数据的一致性处理,同时能够优雅的处理运行时故障,并且具备快速的从故障中恢复的能力。ZAB 协议是整个 Zookeeper 框架的核心所在,其规定了任何时候都需要保证只有一个主进程负责进行消息广播,而如果主进程崩溃了,就需要选出一个新的主进程。主进程的选举机制和消息广播机制是紧密相关的。随着时间的推移,会出现无数个主进程并构成一个主进程序列:P1,P2,...Pe, 其中e表示主进程序列号,也被称作主进程周期。对于这个主进程序列上的任意2个主进程来说,如果e小于e1,那么我们就说 Pe 是Pe1 之前的主进程,通常使用 Pe < Pe1 来表示。需要注意的是,由于各个进程都可能会发生崩溃然后再次恢复,因此会出现这样的情况:存在这样的 Pe 和 Pe1,它们本质上是同一个进程,只是处于不同周期中而已。主进程周期:为了保证主进程每次广播出来的事务消息都是一致的,我们必须确保zab协议只有在充分完成崩溃恢复阶段之后,新的主进程才可以开始生成新的事务消息广播。为了实现这个目的,我们假设各个进程都实现了类似 ready(e) 这样一个函数调用,在运行过程中,zab 协议能够非常明确的告知上层系统(指主进程和其他副本进程)是否可以开始进行事务消息的广播,同时,在调用ready(e)函数之后,zab 还需要为当前主进程设置一个实例值。实例值用于唯一标识当前主进程的周期,在进行消息广播的时候,主进程使用该实例值来设置事务标识中的 epoch 字段---当然,zab需要保证实例值在不同的主进程周期中是全局唯一的。如果一个主进程周期 e 早于另外一个主进程周期e1,那么将其表示为 e<e1。事务:我们假设各个进程都存在一个类似于 transaction(v,z) 这样的函数调用,来实现主进程对状态变更的广播。主进程每次对 transaction(v,z)函数的调用都包含了2个字段:事务内容v 和事务标识z,而每一个事务标识 z=<e,c> 也包含2个组成部分,前者是主进程周期e,后者是当前主进程周期内的事务计数c。我们使用 epoch(z) 来表示一个事务标识中的主进程周期 epoch,使用 counter(z) 来表示事务标识中的事务计数。针对每一个新的事务,主进程都会首先将事务计数c递增。在实际运行中,如果一个事务标识z优先于另外一个事务z1,那么就有2种情况:一种是主进程周期不同,即 epoch(z) < epoch(z1);另外一种情况是主进程周期一样,但是事务计数不同,即 epoch(z) = epoch(z1) 且counter(z) < counter(z1),无论哪种情况,均使用 z < z1 来表示。3.算法描述整个zab协议主要包括消息广播和崩溃恢复2个过程,进一步可以细分为三个阶段,分别是发现(Discovery),同步(Synchronizatioin)和广播(Broadcast)阶段。组成zab协议的每一个分布式进程,会循环的执行这3个阶段,我们将这样一个循环称为一个主进程周期。Fp : Follower f 处理过的最后一个事务 ProposalFzxid : Follower f 处理过的历史事务 Proposal 中最后一个事务 Proposal 的事务标识 ZXIDhf : 每一个 Follower f 通常都已经处理(接受)了不少事务 Proposal,并且会有一个针对已经处理过的事务的集合,并将其表示为 hf,表示 Follower f已经处理过的事务序列。Ie:初始化历史记录,在某一个主进程周期 epoch e 中,当准 Leader 完成阶段一之后,此时它的 hf 就被标记为 Ie.阶段一:发现阶段一主要就是 Leader 选举过程,用于在多个分布式进程中选举出主进程,准 Leader L 和 Follower F的工作流程分别如下:步骤 F.1.1 :Follower F 将自己最后接受的事务 Proposal 的 epoch 值 CEPOCH(Fp)发送给准 Leader L步骤 L.1.1 :当接收来自过半的 Follower 的 CEPOCH(Fp)消息后,准 Leader L 会生成 NEWEPOCH(e1) 消息给这些过半的 Follower。关于这个 epoch 值 e1,准 Leader L 会从所有接收的 CEPOCH(Fp)消息中选出最大的 epoch 值,然后对其进行加1操作,即为 e1。步骤 F.1.2 :当 Follower 接收到来自准 Leader L 的 NEWEPOCH(e1)消息后,如果其检测到当前的 CEPOCH(Fp)值小于e1,那么就会将 CEPOCH(Fp)赋值为 e1,同时向这个准 Leader L反馈 ack 消息。这个反馈消息(ACK-E(Fp,hf))中,包含了当前该 Follower 的 epoch CEPOCH(Fp),以及该Follower 的历史事务 Proposal 集合:hf.当Leader L 接收到来自过半 Follower 的确认消息 Ack 之后,Leader L 就会从这些过半服务器中选出一个 Follower F,并使用其作为初始化事务集合Ie1.关于这个 Follower F 的选取,对于 Quorum 中其他任意一个 Follower F1,F需要满足以下2个条件中的一个:CEPOCH(F1p) < CEPOCH(Fp)(CEPOCH(F1p) = CEPOCH(Fp)) & (F1zxid < zFxxid 或 F1zxid = Fzxid) 至此,zab 协议完成阶段一的工作流程阶段二:同步在完成发现流程之后,就进入到了同步阶段。在这一阶段中,Leader L 和 Follower F的工作流程如下:步骤 L.2.1:Leader L 会将 e1和 Ie1 以 NEWLEADER(e1,Ie1)消息的形式发送给所有 Quorum 中的 Follower.步骤 F.2.1:当 Follower 接收到来自 Leader L 的 NEWLEADER(e1,Ie1)消息后,如果 Follower 发现 CEPOCH(Fp) != e1,那么直接进入下一轮循环,因此此时 Follower 发现自己还在上一轮,或者更上一轮,无法参与本轮同步。如果 CEPOCH(Fp) = e1,那么 Follower 就会执行事务应用操作。具体的,对于每一个事务 Proposal: <v,z> 属于 Ie1,Follower 都会接受<e1,<v,z>>最后,Follower 会反馈给 Leader,表明自己已经接受并处理了所有Ie1中的事务 Proposal.步骤 L.2.2:当 Leader 接收到来自过半 Follower 针对 NEWLEADER(e1,Ie1)的反馈消息后,就会向所有的 Follower 发送 Commit 消息,至此 Leader 完成阶段二。步骤 F.2.2:当 Follower 收到来自 Leader 的 Commit 消息后,就会依次处理并提交所有在 Ie2中未处理的事务。至此 Follower 完成阶段二。阶段三:广播 完成同步阶段之后,zab协议就可以正式开始接收客户端新的事务请求,并进行消息广播。步骤 L.3.1:Leader L 接收到客户端新的事务请求后,会生成对应的事务 Proposal,并根据 zxid 的顺序向所有的 follower 发送提案 <e1,<v,z>>,其中epoch(z)=e1.步骤 F.3.1 :Follower 根据消息接收的先后次序来处理这些来自 Leader 的事务 Proposal,并将它们追加到 hf 中去,之后再次反馈 Leader.步骤 F.3.1:当 leader 接收到来自过半 follower 针对事务 proposal <e1,<v,z>>的 ack 消息后,就会发送 commit<e1,<v,z>> 消息给所有的 follower,要求它们进行事务的提交。步骤 F.3.1:当follower F 接收到来自 leader 的 commit <e1,<v,z>>消息后,就会开始提交事务 proposal<e1,<v,z>>。需要注意的是,此时该 follower F必定已经提交了事务 Proposal<v1,z1>,其中 <v1,z1>属于 hf,z1 < zZ。         4.运行分析在zab协议的设计中,每一个进程都有可能处于下面3种状态:1.LOOKING : Leader 选举阶段2.FOLLOWING : Follower 服务器和 Leader 保持同步状态3.LEADING : Leader 服务器作为主进程领导状态组成 zab 协议的所有进程启动的时候,其初始化状态都是 looking 状态,此时进程组中不存在 leader。所有处于这种状态的进程,都会试图去选举出一个新的leader。随后,如果进程发现已经选举出新的leader了,那么它就会马上切换到 following 状态,并开始和 leader 保持同步。这里,我们将处于 following 的进程称为 follower,将处于 leading 状态的进程称为 leader。考虑到 leader 进程随时会挂掉,当检测出 leader 已经崩溃或者是放弃了领导地位时,其余的 follower 进程就会切换到 looking 状态,并开始新一轮的 leader 选举。因此在 zab 协议运行的过程中,每个进程都会在 leading,following和looking 状态之间不断的切换。一个可用的 leader : 如果一个准 leader Le 接收来自过半的 Follower 进程针对 Le 的 NEWLEADER(e,Ie)反馈消息,那么Le就成为了周期e的 Leader。完成了 Leader 选举以及数据同步之后,zab 协议就进入了原子广播阶段。在这一阶段,leader 会以队列的形式为每一个与自己保持同步的 follower 创建一个操作队列。同一时刻,一个 follower 只能和一个 leader 保持同步,leader 进程与所有的 follower 进程之间都通过心跳检测机制来感知彼此的情况。如果leader能够在超时时间内正常收到心跳检测,那么follower就会一直与该 leader 保持连接。而如果在在指定时间 leader 无法从过半的 follower 进程那里接收到心跳检测,或者是 tcp 连接本身断开了,那么 leader 就会终止当前对周期的领导,并转换到 looking 状态,所有的 follower 也会选择放弃这个leader,同时转换到 looking 状态,之后,所有的进程就会开始新一轮的 leader 选举,并在选举产生新的 leader 之后开始新一轮的主进程周期。4.ZAB 与 Paxos 算法的联系和区别联系:1.两者都存在一个类似于 leader 进程的角色,由其负责协调多个 follower 进程的运行2.leader 进程都会等待超过半数的 follower 做出正确的反馈后,才会将一个提案进行提交3.在 zab 协议中,每个 proposal 中都包含了一个 epoch 值,用来代表当前的 leader 周期,在 paxos 算法中,同样存在这样一个标识,只是名字变成 Bollot在paxos算法中,一个新选举产生的主进程会进行2个阶段的工作。第一阶段被称为读阶段,在这个阶段,这个新的主进程会通过和所有其他进程进行通信的方式来收集上一个主进程提出的提案,并将它们提交。第二阶段被称为写阶段,在这个阶段,当前进程开始提出它自己的提案。在 paxos 算法中,zab 协议额外添加了一个同步阶段,zab 协议也存在一个和 paxos 算法中的读阶段非常类似的过程,被称为发现(Discovery)阶段。在同步阶段中,新的 leader 会确保存在过半的 follower 已经提交了之前 leader 周期的所有事务 proposal。这一同步阶段的引入,能够有效的保证 leader 在新的周期中的提出的事务 proposal 之前,所有的进程都已经完成了对之前所有事务 proposal 的提交。一旦完成同步阶段后,那么 zab 就会执行和 paxos 算法类似的写阶段。总的来说,zab 协议和 paxos 算法的本质区别在于,两者的设计目标不太一样。zab 协议主要用于构建一个高可用的分布式数据库主备系统,例如 zookeeper,而 paxos算法则是用于构建一个分布式的一致性状态机系统。

4.从Paxos到Zookeeper分布式一致性原理与实践--- Zookeeper 与 Paxos相关推荐

  1. 《从Paxos到zookeeper分布式一致性原理与实践》笔记

    <从Paxos到zookeeper分布式一致性原理与实践>笔记 文章目录 <从Paxos到zookeeper分布式一致性原理与实践>笔记 一.概念 二.一致性协调 2.1 2P ...

  2. 《从Paxos到zookeeper分布式一致性原理与实践》

    <从Paxos到zookeeper分布式一致性原理与实践> 一.概念 ACID: Automaticy.consistency.isolation. Durability CAP: con ...

  3. [201502][从 Paxos 到 ZooKeeper][分布式一致性原理与实践][倪超][著]

    [201502][从 Paxos 到 ZooKeeper][分布式一致性原理与实践][倪超][著] http://zookeeper.apache.org 第 1 章 分布式架构 1.1 从集中式到分 ...

  4. 《从Paxos到Zookeeper 分布式一致性原理与实践》

    第1章 分布式架构 1.1 从集中式到分布式 1.1.1 集中式的特点 集中式的特点:部署结构简单(因为基于底层性能卓越的大型主机,不需考虑对服务多个节点的部署,也就不用考虑多个节点之间分布式协调问题 ...

  5. 《从Paxos到ZooKeeper 分布式一致性原理与实践》读书笔记

    一.分布式架构 1.分布式特点 分布性 对等性.分布式系统中的所有计算机节点都是对等的 并发性.多个节点并发的操作一些共享的资源 缺乏全局时钟.节点之间通过消息传递进行通信和协调,因为缺乏全局时钟,很 ...

  6. 《从paxos到zookeeper分布式一致性原理与实践》读书笔记--第二章一致性协议--二阶段提交

    在分布式系统中,每一台机器节点虽然能够知道自己在进行事务操作过程中的结果是成功还是失败但无法直接获取其他分布式系欸但的操作结果.因此,当一个事务需要跨越多个分布式节点的时候为了保持事务的ACID特性, ...

  7. 从Paxos到Zookeeper:分布式一致性原理与实践

    网站 更多书籍点击进入>> CiCi岛 下载 电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍 电子书下载(皮皮云盘-点击"普通下载" ...

  8. Zookeeper分布式一致性原理(四):Zookeeper简介

    zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现数据发布/订阅.负载均衡.命名服务.分布式协调/通知.集群管理.master选举.分布式锁和分布式队列等.Zook ...

  9. Zookeeper分布式一致性原理(八):Zookeeper典型应用场景

    1. 简介 Zookeeper是一个高可用的分布式数据管理和协调框架,并且能够很好的保证分布式环境中数据的一致性.在越来越多的分布式系统(Hadoop.HBase.Kafka)中,Zookeeper都 ...

  10. Zookeeper分布式一致性原理(二):一致性协议

    为了解决分布式一致性问题,在长期的研究过程中,提出了一大批经典的一致性协议和算法,其中最著名的就是2PC和3PC以及Paxos算法了. 1. 2PC和3PC 在分布式系统中,每个节点都明确知道自己事务 ...

最新文章

  1. Hierarchical Attention Networks for Document Classification 阅读笔记
  2. 简单了解一下函数模板
  3. 使计算机工作必不可缺的软件,探讨测绘工程中计算机制图的运用问题(原稿)
  4. 永恒python怎么强化_永恒python加6_pythontip 挑战python (6-10)
  5. HTTP_响应消息_响应头
  6. Linux之RPM 软件管理程序
  7. 谷歌开源缩放模型EfficientNets:ImageNet准确率创纪录,效率提高10倍
  8. java读取txt文件---,java读取TXT文件的方法
  9. 中国新药研发方向与国外存在较大差异
  10. jquery easyui datagrid deleteRow(删除行)的BUG!
  11. 为什么 call 比 apply 快?
  12. svg上传服务器无法显示,让WordPress支持上传SVG格式图片并显示在媒体库中的方法...
  13. NAACL 2022 | FACTPEGASUS:抽象摘要的真实性感知预训练和微调
  14. Numerical Summation of a Series
  15. 移动客户端与服务器通信方式一
  16. chrome 54字体变大问题解决方案
  17. 电位器的作用与原理及注意事项
  18. python简单的加法问题_Python实现20以内加减法练习
  19. 人工智能行业调查研究报告(算法导论调查研究报告)
  20. php把unicode转化成中文实用方法

热门文章

  1. Linux下读写UART串口的代码
  2. python处理识别图片验证码
  3. hdu 1520(树形dp)
  4. 如何实现parseFloat保留小数点后2位
  5. 【OpenCV入门教程之六】 创建Trackbar 图像对比度、亮度值调整(转)
  6. Cocos开发中性能优化工具介绍(一):Xcode中Instruments工具使用
  7. Div 在页面中居中
  8. 水晶报表PUSH方法Demo
  9. R_ggplot2基础(三)
  10. tidyverse —— dplyr包