ZooKeeper原理深入之ZAB原子消息广播协议

文章目录

  • 一、总结
  • 二、ZooKeeper的核心-ZAB协议
    • 2.1 ZAB的作用
    • 2.2 ZAB的原理介绍
    • 2.2 ZAB的两种模式状态
    • 2.3 消息广播的过程
    • 2.4 崩溃恢复
    • 2.5 ZAB节点状态
    • 2.6 Leader选举
      • 服务器启动时Leader选举
      • 服务运行时Leader选举
    • 2.7 ZAB和Paxos对比
  • 三、不同节点的作用
    • 3.1 Leader节点
    • 3.2 Follower节点
    • 3.3 Observer

对其他分布式数据一性协议感兴趣的,可以转到我的另一篇博客:
分布式数据一致性常见协议总结 NWR、Gossip、Paxos、Raft、Lease

一、总结

  1. ZooKeeper是一个以CP为目标的分布式协调服务,没有保证任意时候的可用性。放弃可用性体现在 因为Zookeeper启动时 不可用,节点与集群断开时也不可用,选举状态时也不可用。
  2. ZooKeeper 实现了最终一致性,并不是一个强一致性框架,这点在官网上也有说明。因为除了主节点外,子节点的数据都是异步写入的,子节点又提供读服务这时候数据就是不一致的。这么设计为了满足Zookeeper的写入效率,如果所有节点同步写入效率太低。
  3. ZAB协议 原子广播协议借鉴了paxos算法,处理事务时类似2PC协议的方式
  4. ZK集群要保证一半的机器节点正常运行才能提供服务,因为协议中每次写入数据都需要半数以上节点收到消息才提交,这样只要集群还剩下超过一半节点才能提供服务。那么就一定包含了已提交数据的节点,保证了不会丢失数据。
  5. Zookeeper 推荐奇数节点部署,因为对于可用性来说为某个奇数数量集群增加一台使其变成偶数节点对于提升集群的最大容错服务数没有帮助 所以处于节省资源的角度考虑还是部署奇数节点比较合适
  6. 投票要求超过半数节点,是为了防止脑裂,这是比较有名的 Quorums (法定人数方式) 如果集群被分裂后每超过半数节点,那么就停止提供服务集群无效。

二、ZooKeeper的核心-ZAB协议

2.1 ZAB的作用

  • ZAB协议全称 ZooKeeper Atomic Broadcast 原子消息广播协议。
  • 它并不像paxos一样是一种通用的分布式一致性算法,他是专门为 ZooKeeper 设计的一种支持崩溃恢复的原子广播协议
  • 保证了一致性 ZooKeeper 主要就是依赖ZAB协议来实现分布式数据的一致性,基于该协议Zookeeper实现了一种主备模式的系统架构来保持集群中副本数据一致性。具体就是使Leader节点接收数据变更的事物向副本进程广播。
  • **可用性强 **在ZooKeeper集群中,同一时刻只能有一个主进程来处理和广播服务器状态变更。并且ZAB保证了当这个主进程异常时,能迅速恢复整个系统的正常状态。

2.2 ZAB的原理介绍

ZooKeeper原理深入之ZAB原子消息广播协议_第1张图片
ZAB协议的核心是定义了对于会改变 ZooKeeper 数据状态的事物请求的处理方式

所有事务请求必须由⼀个全局唯⼀的服务器来协调处理,这样的服务器被称为Leader服务器,余下的服务器则称为Follower服务器,Leader服务器负责将⼀个客户端事务请求转化成⼀个事务Proposal(提议),并将该Proposal分发给集群中所有的Follower服务器,之后Leader服务器需要等待所有Follower服务器的反馈,⼀旦超过半数的Follower服务器进⾏了正确的反馈后,那么Leader就会再次向所有的Follower服务器分发Commit消息,要求其将前⼀个Proposal进⾏提交。

2.2 ZAB的两种模式状态

ZAB 协议包括两种基本的模式:崩溃恢复模式和消息广播模式
崩溃恢复模式

  • 服务启动时,或者Leader服务器因网络或者宕机从集群中退出时,ZAB协议就会进入崩溃恢复模式。
  • 同时开始选举新的Leader服务器,产生新的Leader服务器,并且过半数的机器与改Leader完了状态同步后。ZAB协议就会退出恢复模式,状态同步就是节点间数据同步是为了保证过半的机器能够和Leader节点数据状态一致

消息广播模式

  • 集群过半的Follower服务器完成状态同步后,那么服务集群就进入了消息广播模式
  • 此时如果一台ZAB协议的机器启动加入到集群,那么加入的服务器会自觉地进入数据恢复模式,会找到Leader节点并且与其进行数据同步,然后一起加入到消息广播流程中。
  • Zookeeper只允许唯⼀的⼀Zookeeper只允许唯⼀的⼀个Leader服务器来进行事物请求处理,Leader收到事情请求后,会发起一轮广播协议,而非Leader节点收到事物请求会将其转发给Leader节点处理。

2.3 消息广播的过程

ZAB协议的消息⼴播过程使⽤原⼦⼴播协议,类似于⼀个⼆阶段提交过程,针对客户端的事务请求,Leader服务器会为其⽣成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各⾃的选票,最后进⾏事务提交。
ZooKeeper原理深入之ZAB原子消息广播协议_第2张图片
在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响应后,就会⼴播⼀个Commit消息给所有的Follower服务器以通知其进⾏事务提交,同时Leader⾃身也会完成对事务的提交,⽽每⼀个Follower服务器在接收到Commit消息后,也会完成对事务的提交。

2.4 崩溃恢复

崩溃后需要做的

  1. ZAB 需要保证崩溃后的数据一致性
  2. 要让集群能快速的选出新的Leader节点
  3. 要让Leader节点和其他节点快速知道谁是Leader节点

Leader崩溃的场景
已进入集群节点的需要恢复

  1. 场景1 Leader 提出事务后收到了超过半数的ACK,本地已提交准备通知子节点的时候死了
  2. 场景2 Leader 提出事务后 只有部分节点回复了ACK Leader还未本地提交就死了

未进入集群节点的需要抛弃

  1. 场景1:leader收到事务还未发proposal 就死了
  2. 场景2:Leader 提出proposal后 Leader和收到prposal的都死了

ZAB的恢复崩溃恢复方式
ZAB算法会在崩溃恢复时,选举出集群中拥有最高ZXID的节点作为Leader这样就可以保证这个Leader拥有所有已提交的提案。这样就省去了Leader检查Proposal的提交和丢弃工作这一步了。

数据同步

  1. 重新选举出Leader后,在正式接受客户端十五请求前,Leader会先确认事务日志中所有的Proposal都已经被集群中过半的机器提交了,即完成数据同步了。
  2. 所有正常运行的机器节点,要么成为Leader 要么成为Follower并且和Leader保持同步。Leader服务器需要确保所有的Follower服务器都能接收到每一条事务Proposal,并且能正确的保存已提交的事务到其内存数据库中。
  3. Leader节点会为每个Follower服务器准备一个队列,将没有被Follower同步的事务以Proposal的消息诸葛发送给Follower服务器,并且每个Proposal后面再跟随一个Commit消息,以表示事务已被提交。。
  4. 等到所有的Follower服务器都完全同步Leader节点的事务后,Leader服务器就会将其加入到真正可用的Follower列表中对外提供服务

2.5 ZAB节点状态

ZAB协议中,节点都有三个状态

  • LOOKING 对应Leader选举状态
  • FOLLOWING Follower服务器和leader保持同步状态
  • LEADING Leader服务器作为集群主进程状态

所有进程初始状态都是LOOKING状态,此时不存在Leader,接下来,进程会试图选举出⼀个新的Leader,之后,如果进程发现已经选举出新的Leader了,那么它就会切换到FOLLOWING状态,并开始和Leader保持同步,处于FOLLOWING状态的进程称为Follower,LEADING状态的进程称为Leader,当Leader崩溃或放弃领导地位时,其余的Follower进程就会转换到LOOKING状态开始新⼀轮的Leader选举。
  ⼀个Follower只能和⼀个Leader保持同步,Leader进程和所有的Follower进程之间都通过⼼跳检测机制来感知彼此的情况。若Leader能够在超时时间内正常收到⼼跳检测,那么Follower就会⼀直与该Leader保持连接,⽽如果在指定时间内Leader⽆法从过半的Follower进程那⾥接收到⼼跳检测,或者TCP连接断开,那么Leader会放弃当前周期的领导,并转换到LOOKING状态,其他的Follower也会选择放弃这个Leader,同时转换到LOOKING状态,之后会进⾏新⼀轮的Leader选举。

2.6 Leader选举

Leader选举时保证数据一致性的关键所在,也是 ZooKeeper 的重要技术。在服务刚启动时或者服务器运行期间无法和Leader保持连接时

服务器启动时Leader选举

如果要进行Leader选举,则至少需要2台机器上线,现在假设有三台机器组成的集群。

  1. 如果只启动一台机器 server1 此时无法进行选举。
  2. Server2 启动时,此时server1 和server2 可以互相通信,此时发现不存在Leader
  3. 这时Server1 和Server2 进入 LOOKING 状态开始进行Leader选举
  4. 发起投票
    1. 初始时 server1 (myid=1) 和 server2 (myid=2) 都会把自己当作Leader服务器来进行投票
    2. 每次投票会包含推选的服务器的 myid 和 ZXID 表示为 (myid,ZXID) 此时 server1发起的为 (1,0)server2 发起的投票为(2,0)
  5. 接受投票 每个服务器收到投票请求后,首先会判断投票是否过期 例如检查投票是否来自 LOOKING 状态的服务器。
  6. 处理投票 服务器检查别人发起的投票和自己的进行对比
    1. 优先检查ZXID ZXID较大说明其数据更新,优先成为Leader
    2. ZXID相同则比较myid myid较大的作为Leader
  7. server1 发起的投票是(1,0) 收到的投票是(2,0) 则更新自己的投票为(2,0)
  8. server2 则不需要更新自己的投票
  9. 统计投票
    1. 每次投票后统计所有服务器的投票,判断是否有过半的机器收到相同的投票信息
    2. 过半 是指大于集群机器数量的一半 这里就是 大于等于(n/2+1)此处大于等于2即可
    3. 对于server1 和server2 来说,统计到集群中两台机器都是 (2,0) 达到了过半的要求
    4. 所以server2 成为了Leader
    5. server1 成为Follower状态 server2 成为leader状态
    6. 此时如果server3 加入,此时集群中存在leader 在向Leader进行数据同步后成为Follower

服务运行时Leader选举

在ZooKeeper集群正常运⾏过程中,⼀旦选出⼀个Leader,那么所有服务器的集群⻆⾊⼀般不会再发⽣变化——也就是说,Leader服务器将⼀直作为集群的Leader,即使集群中有⾮Leader机器挂了或是有新机器加⼊集群也不会影响Leader。但是⼀旦Leader所在的机器挂了,那么整个集群将暂时⽆法对外服务,⽽是进⼊新⼀轮的Leader选举。服务器运⾏期间的Leader选举和启动时期的Leader选举基本过程是⼀致的
我们还是假设当前正在运⾏的 ZooKeeper 机器由 3 台机器组成,分别是 Server1、Server2和Server3,当前的Leader是Server2。假设在某⼀个瞬间,Leader挂了,这个时候便开始了Leader选举。
变更状态
Leader挂后,余下的⾮Observer服务器都会将⾃⼰的服务器状态变更为LOOKING,然后开始进⼊Leader选举过程。

  1. Leader挂后,余下的⾮Observer服务器都会将⾃⼰的服务器状态变更为LOOKING,然后开始进⼊Leader选举过程。
  2. 在运⾏期间,每个服务器上的ZXID可能不同,此时假定Server1的ZXID为123,Server3的ZXID为122;在第⼀轮投票中,Server1和Server3都会投⾃⼰,产⽣投票(1, 123),(3, 122),然后各⾃将投票发送给集群中所有机器。
  3. 接收来⾃各个服务器的投票,与启动时过程相同
  4. 处理投票。与启动时过程相同,此时,Server1将会成为Leader
  5. 统计投票。与启动时过程相同
  6. 改变服务器的状态。与启动时过程相同

2.7 ZAB和Paxos对比

联系:

  1. 都有一个类似Leader进程的角色,ZAB中为Leader Paxos中是Proposer
  2. Leader进程都会等待超过半数的Follower/Acceptor
  3. ZAB协议中 每个Proposal都包含一个epoch值,代表Leader的周期,Paxos中也有这样的标识,称为Ballot。Raft中也有称为**TermId **
  4. 数据提交过程都类似于2阶段提交协议

区别:

  1. paxos新选举的主进程开始工作时,首先是读阶段,和其他进程通信手机主进程的提议,然后将其提交。第二阶段是写阶段,主进程开始提出自己的提议
  2. ZAB 的主进程开始正常工作前,会有个同步阶段,主进程会确保上一个leader周期的所有事物都被过半的flower提交。之后再开始自己新的任期的事物提交。
  3. ZAB处于对写入速度的考虑并没有实现强一致性,paxos作为一个共识算法则不用考虑这个。

三、不同节点的作用

3.1 Leader节点

Leader服务器是Zookeeper集群⼯作的核⼼,其主要⼯作有以下两个
  (1) 事务请求的唯⼀调度和处理者,保证集群事务处理的顺序性。
  (2) 集群内部各服务器的调度者。

请求处理链
使⽤责任链来处理每个客户端的请求是Zookeeper的特⾊,Leader服务器的请求处理链如下。
ZooKeeper原理深入之ZAB原子消息广播协议_第3张图片

  1. PrepRequestProcessor 请求预处理器,也是leader服务器中的第⼀个请求处理器。在Zookeeper中,那些会改变服务器状态的请求称为事务请求(创建节点、更新数据、删除节点、创建会话等)PrepRequestProcessor能够识别出当前客户端请求是否是事务请求。对于事务请求,PrepRequestProcessor处理器会对其进⾏⼀系列预处理,如创建请求事务头、事务体、会话检查、ACL检查和版本检查等。
  2. ProposalRequestProcessor。事务投票处理器。也是Leader服务器事务处理流程的发起者,对于⾮事务性请求,ProposalRequestProcessor会直接将请求转发到CommitProcessor处理器,不再做任何处理,⽽对于事务性请求,处理将请求转发到CommitProcessor外,还会根据请求类型创建对应的Proposal提议,并发送给所有的Follower服务器来发起⼀次集群内的事务投票。同时,ProposalRequestProcessor还会将事务请求交付给SyncRequestProcessor进⾏事务⽇志的记录。
  3. SyncRequestProcessor。事务⽇志记录处理器。⽤来将事务请求记录到事务⽇志⽂件中,同时会触发Zookeeper进⾏数据快照。
  4. AckRequestProcessor。负责在SyncRequestProcessor完成事务⽇志记录后,向Proposal的投票收集器发送ACK反馈,以通知投票收集器当前服务器已经完成了对该Proposal的事务⽇志记录。
  5. CommitProcessor。事务提交处理器。对于⾮事务请求,该处理器会直接将其交付给下⼀级处理器处理;对于事务请求,其会等待集群内 针对Proposal的投票直到该Proposal可被提交,利⽤CommitProcessor,每个服务器都可以很好地控制对事务请求的顺序处理。
  6. ToBeCommitProcessor。该处理器有⼀个toBeApplied队列,⽤来存储那些已经被CommitProcessor处理过的可被提交的Proposal。其会将这些请求交付给FinalRequestProcessor处理器处理,待其处理完后,再将其从toBeApplied队列中移除。
  7. FinalRequestProcessor。⽤来进⾏客户端请求返回之前的操作,包括创建客户端请求的响应,针对事务请求,该处理器还会负责将事务应⽤到内存数据库中。

3.2 Follower节点

Follower服务器是Zookeeper集群状态中的跟随者,其主要⼯作有以下三个:

  1. 处理客户端⾮事务性请求(读取数据),转发事务请求给Leader服务器。
  2. 参与事务请求Proposal的投票。
  3. 参与Leader选举投票。

和leader⼀样,Follower也采⽤了责任链模式组装的请求处理链来处理每⼀个客户端请求,由于不需要对事务请求的投票处理,因此Follower的请求处理链会相对简单,其处理链如下
ZooKeeper原理深入之ZAB原子消息广播协议_第4张图片
和 Leader 服务器的请求处理链最⼤的不同点在于,Follower 服务器的第⼀个处理器换成了FollowerRequestProcessor处理器,同时由于不需要处理事务请求的投票,因此也没有了ProposalRequestProcessor处理器。

  1. FollowerRequestProcessor 其⽤作识别当前请求是否是事务请求,若是,那么Follower就会将该请求转发给Leader服务器,Leader服务器在接收到这个事务请求后,就会将其提交到请求处理链,按照正常事务请求进⾏处理。
  2. SendAckRequestProcessor 其承担了事务⽇志记录反馈的⻆⾊,在完成事务⽇志记录后,会向Leader服务器发送ACK消息以表明⾃身完成了事务⽇志的记录⼯作。

3.3 Observer

Observer是ZooKeeper⾃3.3.0版本开始引⼊的⼀个全新的服务器⻆⾊。从字⾯意思看,该服务器充当了⼀个观察者的⻆⾊——其观察ZooKeeper集群的最新状态变化并将这些状态变更同步过来。
Observer服务器在⼯作原理上和Follower基本是⼀致的,对于⾮事务请求,都可以进⾏独⽴的处理,⽽对于事务请求,则会转发给Leader服务器进⾏处理。
和Follower唯⼀的区别在于,Observer不参与任何形式的投票,包括事务请求Proposal的投票和Leader选举投票。简单地讲,Observer服务器只提供⾮事务服务,通常⽤于在不影响集群事务处理能⼒的前提下提升集群的⾮事务处理能⼒。
Follower的处理链
ZooKeeper原理深入之ZAB原子消息广播协议_第5张图片
另外需要注意的⼀点是,虽然在图中可以看到,Observer 服务器在初始化阶段会将SyncRequestProcessor处理器也组装上去,但是在实际运⾏过程中,Leader服务器不会将事务请求的投票发送给Observer服务器。

你可能感兴趣的:(架构,#,ZooKeeper,zookeeper,分布式,云原生,一致性协议,微服务)