Paxos算法详解

兰伯特提出的Paxos算法包括2个部分:

  • 一个是Basic Paxos算法,描述的是多节点之间如何就某个值(提案value)达成共识
  • 另一个是Multi-Paxos思想,描述的是执行多个Basic Paxos实例,就一系列值达成共识

1、Basic Paxos

一个分布式集群由节点A、B、C组成,提供只读KV存储服务。创建只读变量的时候,必须要对它进行赋值,而且这个值后续没办法修改。因此一个节点创建只读变量后就不能再修改它了,所以所有节点必须要先对只读变量的值达成共识,然后所有节点再一起创建这个只读变量

当有多个客户端访问这个系统,试图创建同一个只读变量,客户端1试图创建值为3的X,客户端2试图创建值为7的X,这样如何达成共识,实现各节点上X值的一致呢?

Paxos算法详解_第1张图片

1)、Basic Paxos中的三种角色

在Basic Paxos中,有提议者(Proposer)、接受者(Acceptor)、学习者(Learner)三种角色,他们之间的关系如下:

Paxos算法详解_第2张图片

  • 提议者(Proposer):提议一个值,用于投票表决。集群中收到客户端请求的节点是提议者
  • 接受者(Acceptor):对每个提议的值进行投票,并存储接受的值。集群中所有节点都在扮演接受者的角色,参与共识协商,并接受和存储数据

一个节点可以身兼多个角色。如下图,一个3节点的集群,1个节点收到了请求,那么该节点将作为提议者发起二阶段提交,然后这个节点和另外2个节点一起作为接受者进行共识协商

Paxos算法详解_第3张图片

  • 学习者(Learner):被告知投票的结果,接受达成共识的值,存储保存,不参与投票的过程。一般来说,学习者是数据备份节点,比如Master-Slave模型中的Slave,被动地接受数据,容灾备份

这3种角色在本质上代表的是3种功能:

  • 提议者代表的是接入和协调功能,收到客户端请求后,发起二阶段提交,进行共识协商
  • 接受者代表投票协商和存储数据,对提议的值进行投票,并接受达成共识的值,存储保存
  • 学习者代表存储数据,不参与共识协商,只接受达成共识的值,存储保存

2)、如何达成共识

在Basic Paxos中,兰伯特使用提案代表一个提议,提案中包含了提案编号和提议值。下面使用[n, v]代表一个提案,其中n为提案编号,v为提议值

假设客户端1的提案编号为1,客户端2的提案编号为5,并假设节点A、B先收到来自客户端1的准备请求,节点C先收到来自客户端2的准备请求

1)准备(Prepare)阶段

首先客户端1、2作为提议者,分别向所有接受者发送包含提案编号的准备请求:

Paxos算法详解_第4张图片

在准备请求中是不需要指定提议的值的,只需要携带提案编号就可以了

接着,当节点A、B收到提案编号为1的准备请求,节点C收到提案编号为5的准备请求后:

Paxos算法详解_第5张图片

  • 由于之前没有通过任何提案,所以节点A、B将返回一个尚无提案的响应。也就是说节点A和B在告诉提议者,我之前没有通过任何提案,并承若以后不再响应提案编号小于等于1的准备请求,不会通过编号小于1的提案
  • 节点C将返回一个尚无提案的响应,并承诺以后不再响应提案编号小于等于5的准备请求,不会通过编号小于5的提案

当节点A、B收到提案编号为5的准备请求,和节点C收到提案编号为1的准备请求的时候,将进行如下处理:

Paxos算法详解_第6张图片

  • 当节点A、B收到提案编号为5的准备请求的时候,因为提案编号5大于它们之前响应的准备请求的提案编号1,而且两个节点都没有通过任何提案,所以它将返回一个尚无提案的响应,并承诺以后不再响应提案编号小于等于5的准备请求,不会通过编号小于5的提案
  • 当节点C收到提案编号为1的准备请求的时候,由于提案编号1小于它之前响应的准备请求的提案编号5,所以丢弃该准备请求,不做响应

2)接受(Accept)阶段

第二个阶段也就是接受阶段,首先客户端1、2在收到大多数节点的准备响应之后,会分别发送接受请求:

Paxos算法详解_第7张图片

  • 当客户端1收到大多数的接受者(节点A、B)的准备响应后,根据响应中提案编号最大的提案的值,设置接受请求中的值。因为该值在来自节点A、B的准备响应中都为空(尚无提案),所以就把自己的提议值3作为提案的值,发送接受请求[1, 3]
  • 当客户端2收到大多数的接受者的准备响应后(节点A、B、C),根据响应中提案编号最大的提案的值,来设置接受请求中的值。因为该值在来自节点A、B、C的准备响应都为空(尚无提案),所以就把自己的提议值7作为提案的值,发送接受请求[5, 7]

当3个节点收到2个客户端的提案请求时,会进行这样的处理:

Paxos算法详解_第8张图片

  • 当节点A、B、C收到接受请求[1, 3]的时候,由于提案的提案编号1小于3各节点承诺能通过的提案的最小提案编号5,所以提案[1, 3]将被拒绝
  • 当节点A、B、C收到接受请求[5, 7]的时候,由于提案的编号5不小于3个节点承诺能通过的提案的最小提案编号5,所以就通过提案[5, 7],也就是接受了值7,3个节点就X值为7达成了共识

如果集群中有学习者,当接收者通过了一个提案时,就通知给所有的学习者。当学习者发现大多数的接受者都通过了某个提案,那么它也通过该提案,接受该提案的值

3)、小结

Basic Paxos是通过二阶段提交的方式来达成共识的,而且还实现了容错,大多数节点都同意的原则赋予了Basic Paxos容错的能力,让它能够容忍少于一半的节点的故障

本质上,提案编号的大小代表着优先级。根据提案编号的大小,接受者保证3个承诺:

  • 如果准备请求的提案编号,小于等于接受者已经响应的准备请求的提案编号,那么接受者将承诺不响应这个准备请求
  • 如果接受请求的提案编号,小于接受者已经响应的准备请求的提案编号,那么接受者将承诺不通过这个提案
  • 如果接受者之前有通过提案,那么接受者将承诺,会在准备请求的响应中,包含已经通过的最大编号的提案信息

4)、思考题

如果节点A、B已经通过了提案[5, 7],节点C未通过任何提案,那么当客户端3提案编号为9时,通过Basic Paxos执行SET X = 6,最终3个节点上X值是多少呢

最终节点上的值应该是[9, 7],过程如下:

  1. 在准备阶段,节点C收到客户端3的准备请求[9, 6],因为节点C未收到任何提案,所以返回尚无提案的响应。这时如果节点C收到了之前客户端的准备请求[5, 7],根据提案编号5小于它之前响应的准备请求的提案编号9,会丢弃该准备请求
  2. 客户端3发送准备请求[9, 6]给节点A、B,这时因为节点A、B已经通过了提案[5, 7],根据“如果接受者之前有通过提案,那么接受者将承诺会在准备请求的响应中,包含已经通过的最大编号的提案信息”的原则,节点A、B会返回[5, 7]给客户端3
  3. 客户端3发送接受请求[9, 7]给节点A、B、C(这里使用的是准备阶段的最大提议编号和已经被通过的值),因为此时请求编号9不小于之前的请求编号,所以所有节点接受该请求[9, 7]

2、Multi-Paxos

Basic Paxos只能就单个值达成共识,一旦遇到为一系列的值实现共识的时候,它就不管用了

兰伯特提到的Multi-Paxos是一种思想,不是算法。而Multi-Paxos算法是一个统称,它是指基于Multi-Paxos思想,通过多个Basic Paxos实例实现一系列值的共识的算法

1)、兰伯特关于Multi-Paxos的思考

Basic Paxos是通过二阶段提交来达成共识的。在第一阶段,也就是准备阶段,接收到大多数准备响应的提议者,才能发起接受请求进入第二阶段(接受阶段):

Paxos算法详解_第9张图片

如果直接通过多次执行Basic Paxos实例,来实现一系列值的共识,就会存在这样几个问题:

  • 如果多个提议者同时提交提案,可能出现因为提案编号冲突,在准备阶段没有提议者接收到大多数准备响应,协商失败,需要重新协调。比如,一个5节点的集群,如果3个节点作为提议者同时提案,就可能发生因为没有提议者接受大多数响应(比如1个提议者接收1个准备响应,另外2个提议者分别接收到2个准备响应)而准备失败,需要重新协调
  • 2轮RPC通讯(准备阶段和接受阶段)往返消息多、耗性能、延迟大

2)、领导者(Leader)

通过引入领导者节点来解决多个提议者同时提交提案可能出现因为提案编号冲突的问题

领导者节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提案冲突的情况了:

Paxos算法详解_第10张图片

在论文中,兰伯特没有说如何选举领导者,需要我们在实现Multi-Paxos算法的时候自己实现。 比如在Chubby中,主节点(也就是领导者节点)是通过执行Basic Paxos算法,进行投票选举产生的

3)、优化Basic Paxos执行(2轮RPC通讯)

可以采用当领导者处于稳定状态时,省掉准备阶段,直接进入接受阶段这个优化机制,优化Basic Paxos执行。也就是说,领导者节点上序列中的命令是最新的,不再需要通过准备请求来发现之前被大多数节点通过的提案,领导者可以独立指定提案中的值。这时,领导者在提交命令时,可以省掉准备阶段,直接进入接受阶段:

准备阶段的意义,是发现接受者节点上,已经通过的提案的值。领导者节点上,序列中的命令是最新的,不再需要通过准备请求来发现之前被大多数节点通过的提案,领导者可以独立指定提案中的值

Paxos算法详解_第11张图片

和重复执行Basic Paxos相比,Multi-Paxos引入领导者节点之后,因为只有领导者节点一个提议者,只有它说了算,所以就不存在提案冲突。另外,当主节点处于稳定状态时,就省掉准备阶段,直接进入接受阶段,所以在很大程度上减少了往返的消息数,提升了性能,降低了延迟

4)、Chubby的Multi-Paxos实现

Chubby中通过引入主节点,实现了兰伯特提到的领导者(Leader)节点的特性。也就是说,主节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提交提案冲突的情况了

在Chubby中,主节点是通过执行Basic Paxos算法,进行投票选举产生的,并且在运行过程中,主节点会通过不断续租的方式来延长租期。如果主节点故障了,那么其他的节点又会投票选举出最新的主节点,也就是说主节点是一直存在的,而且是唯一的

在Chubby中实现了兰伯特提到的,当领导者处于稳定状态时,省掉准备状态,直接进入接受阶段这个优化机制

在Chubby中页实现了成员变更,以此保证节点变更的时候集群的平稳运行

最后,在Chubby中为了实现强一致性,读操作也只能在主节点上执行。也就是说,只要数据写入成功,之后所有的客户端督导的数据都是一致的(只能在主节点进行读操作,效果相当于单机,对吞吐量和性能有所影响)

  • 所有的读请求和写请求都由主节点来处理。当主节点从客户端接收到写请求后,作为提议者,执行Basic Paxos实例,将数据发送给所有的节点,并且在大多数的服务器接受了这个写请求之后,再响应给客户端成功

Paxos算法详解_第12张图片

  • 当主节点接收到读请求后,主节点只需要查询本地数据,然后返回给客户端就可以了

Paxos算法详解_第13张图片

参考:

05 | Paxos算法(一):如何在多个节点间确定某变量的值?

06 | Paxos算法(二):Multi-Paxos不是一个算法,而是统称

你可能感兴趣的:(分布式协议与算法,Basic,Paxos算法,Multi-Paxos思想)