强一致性算法Paxos、Raft、ZAB

在B站上一个讲这三个算法的视频网址https://www.bilibili.com/video/av21667358

Paxos协议

Basic paxos算法中,分为4种角色:

  • Client: 系统外部角色,产生议题者,像民众
  • Proposer :接收议题请求,像集群提出议题(propose),并在冲突发生时,起到冲突调节的作用,像议员
  • Acceptor:提议的投票者和决策者,只有在形成法定人数(一般是majority多数派)时,提议才会被最终接受,像国会
  • Learner:最终提议的接收者,backup,对集群的已执行没有什么影响,像记录员

Paxos有三种实现版本

  1. Basic Paxos版本
  2. Multi Paxos版本
  3. Fast Paxos版本

两个阶段

Prepare阶段

  1. Proposer 生成提案编号 Mn, 向Quorum 广播该编号。
  2. Acceptor 收到Prepare Mn 之后
    1. 如果比已接受提案编号大,则接受Mn, 并承诺不再接受小于Mn 的提案,将已接收的编号最大提案通过返回ACK 给Proposer。
    2. 否则忽略Prepare Mn
  3. Proposer 收到Quorum 数量的ACK 之后,则进入提交阶段。否则重新开始Prepare 阶段。

Accept阶段

  1. Proposer 选取ACK 中编号最大的提案的Value 作为Vn, 向Quorum 广播 Accept [Mn, Vn]。
  2. Acceptor 收到Accept [Mn, Vn] 之后
    1. 若提案不违背承诺,则接受该提案,并返回ACK
    2. 否则忽略

Basic Paxos版本

该版本是最基本的版本,由多个proposer和多个acceptor组成

该版本的问题是,

  • 一个完整的事务,需要两次RPC远程调用,分别是Prepare阶段和Accpet阶段。效率不高
  • 因为是多个proposer可以都提交提案,因此会出现活锁问题,Proposer1提出了M1的提案,并完成的Prepare阶段。与此同时,Proposer2提出了一个新的提案M2(M2>M1),同样也完成了Prepare阶段,于是Acceptor承诺不再批准编号小于M2的提案。当P1进入Accept阶段时,其发出的Accept请求将被Acceptor忽略。于是Proposer1再次进入Prepare阶段并提出一个编号为M3(M3>M2)的提案,而这又会让Proposer2的M2在第二阶段的Accept请求被忽略,如此陷入死循环

Multi Paxos版本

该版本只有一个Leader Proposer,只有Leader Proposer可以提出提案,Leader Proposer通过选举产生。

选举一个Leader Proposer的时候,需要进行投标,当一个Leader选举出来之后,该Leader发出的提案就可以直接进入Accpet阶段。

Raft协议

raft 简化版的Multi Paxos,划分了三个子问题

  • Leader Electtion
  • Log Replication
  • Safety

重定义了三个角色

  • eader
  • Fllower
  • Candidate

这个解释的非常明白
原理动画解释:https://http://thesecretlivesofdata.com/raft/

这个是怎样选举的leader,某个节点宕机了怎么解决的详细动画演示
场景测试:http://raft.github.io

ZAB协议

基本与Raft相同,在一些名词叫起来是有区别的

ZAB将Leader的一个生命周期叫做epoch,而Raft称之为term

实现上也有些许不同,如raft保证日志的连续性,心跳是Leader向Follower发送,而ZAB方向与之相反

术语说明:

ZXID:高32位是epoch,表示Leader周期,单调递增;低32位,Leader产生一个新的事务proposer时,该计数器会加1(在一个Leader周期里是单调递增,epoch变更后从0开始)

SID:服务器ID,用来唯一标识一台ZooKeeper集群中的服务器,每台机器不能重复,和myid的值一致。

vote_sid:接收到的投票信息中所推举的Leader服务器的SID

vote_zxid:接收到的投票信息中所推举的Leader服务器的ZXID

self_sid:当前服务器自己的SID

self_zxid:当前服务器自己的ZXID

electionEpoch:当前服务器的选举轮次。

Leader选举

1.变更状态:如果是运行过程中Leader挂了,则会有这一步,非Observer服务器会将自己的服务器状态变更为LOOKING(寻找Leader状态),然后进入Leader选举流程

2.每个Server会发出一个投票 vote[self_id,self_zxid]

3.接收来自各个Server的投票 vote[vote_sid,vote_zxid]

4.处理投票

  •   先比较ZXID,ZXID比较大的服务器优先作为Leader

         如果vote_zxid > self_zxid,就认可收到的投票,并再次将该投票发送出去

         如果vote_zxid < self_zxid,就坚持自己的投票,不做任何变更

  •   如果ZXID相同的话,那么比较myid,myid比较大的服务器作为Leader服务器。

          如果vote_sid > self_sid,就认可收到的投票,并再次将该投票发送出去

          如果vote_sid < self_sid,那么就坚持自己的投票,不做任何变更

5.统计投票:判断是否已经有过半的机器Quorum接收到相同的投票信息,如果存在一个服务器得到过半的票数,那么得到过半票数的机器作为Leader,终止投票。否则进入步骤3,进入到新一轮的投票选举中。

6.改变服务器状态:确定Leader后,每个服务器会更新自己的状态,如果是Follower,那么就变更为FOLLOWING(跟随者状态),如果是Leader,那么就变更为LEADING(领导者状态)

         注意:选举出一个leader后,服务器不会马上更新状态,而是会等待一段时间(默认是200毫秒)来确定是否有新的更优的投票。

Leader同步

由于上述选举过程保证了 Leader 必然拥有最大zxid, Leader 只需要向Follower 同步自己的历史提案即可。

  1. 若Follower 拥有 Leader 没有的提案,则 truncat掉。
  2. 若Follower的epoch = 当前leader的epoch,落后则根据log, reply 历史transcation
  3. 若落后太多,则直接同步 snapshot,再replay transaction log.

参考理解分布式一致性:Paxos协议之Multi-Paxos

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章