兰伯特提出的Paxos算法包括2个部分:
一个分布式集群由节点A、B、C组成,提供只读KV存储服务。创建只读变量的时候,必须要对它进行赋值,而且这个值后续没办法修改。因此一个节点创建只读变量后就不能再修改它了,所以所有节点必须要先对只读变量的值达成共识,然后所有节点再一起创建这个只读变量
当有多个客户端访问这个系统,试图创建同一个只读变量,客户端1试图创建值为3的X,客户端2试图创建值为7的X,这样如何达成共识,实现各节点上X值的一致呢?
在Basic Paxos中,有提议者(Proposer)、接受者(Acceptor)、学习者(Learner)三种角色,他们之间的关系如下:
一个节点可以身兼多个角色。如下图,一个3节点的集群,1个节点收到了请求,那么该节点将作为提议者发起二阶段提交,然后这个节点和另外2个节点一起作为接受者进行共识协商
这3种角色在本质上代表的是3种功能:
在Basic Paxos中,兰伯特使用提案代表一个提议,提案中包含了提案编号和提议值。下面使用[n, v]代表一个提案,其中n为提案编号,v为提议值
假设客户端1的提案编号为1,客户端2的提案编号为5,并假设节点A、B先收到来自客户端1的准备请求,节点C先收到来自客户端2的准备请求
1)准备(Prepare)阶段
首先客户端1、2作为提议者,分别向所有接受者发送包含提案编号的准备请求:
在准备请求中是不需要指定提议的值的,只需要携带提案编号就可以了
接着,当节点A、B收到提案编号为1的准备请求,节点C收到提案编号为5的准备请求后:
当节点A、B收到提案编号为5的准备请求,和节点C收到提案编号为1的准备请求的时候,将进行如下处理:
2)接受(Accept)阶段
第二个阶段也就是接受阶段,首先客户端1、2在收到大多数节点的准备响应之后,会分别发送接受请求:
当3个节点收到2个客户端的提案请求时,会进行这样的处理:
如果集群中有学习者,当接收者通过了一个提案时,就通知给所有的学习者。当学习者发现大多数的接受者都通过了某个提案,那么它也通过该提案,接受该提案的值
Basic Paxos是通过二阶段提交的方式来达成共识的,而且还实现了容错,大多数节点都同意的原则赋予了Basic Paxos容错的能力,让它能够容忍少于一半的节点的故障
本质上,提案编号的大小代表着优先级。根据提案编号的大小,接受者保证3个承诺:
如果节点A、B已经通过了提案[5, 7],节点C未通过任何提案,那么当客户端3提案编号为9时,通过Basic Paxos执行SET X = 6,最终3个节点上X值是多少呢
最终节点上的值应该是[9, 7],过程如下:
Basic Paxos只能就单个值达成共识,一旦遇到为一系列的值实现共识的时候,它就不管用了
兰伯特提到的Multi-Paxos是一种思想,不是算法。而Multi-Paxos算法是一个统称,它是指基于Multi-Paxos思想,通过多个Basic Paxos实例实现一系列值的共识的算法
Basic Paxos是通过二阶段提交来达成共识的。在第一阶段,也就是准备阶段,接收到大多数准备响应的提议者,才能发起接受请求进入第二阶段(接受阶段):
如果直接通过多次执行Basic Paxos实例,来实现一系列值的共识,就会存在这样几个问题:
通过引入领导者节点来解决多个提议者同时提交提案可能出现因为提案编号冲突的问题
领导者节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提案冲突的情况了:
在论文中,兰伯特没有说如何选举领导者,需要我们在实现Multi-Paxos算法的时候自己实现。 比如在Chubby中,主节点(也就是领导者节点)是通过执行Basic Paxos算法,进行投票选举产生的
可以采用当领导者处于稳定状态时,省掉准备阶段,直接进入接受阶段这个优化机制,优化Basic Paxos执行。也就是说,领导者节点上序列中的命令是最新的,不再需要通过准备请求来发现之前被大多数节点通过的提案,领导者可以独立指定提案中的值。这时,领导者在提交命令时,可以省掉准备阶段,直接进入接受阶段:
准备阶段的意义,是发现接受者节点上,已经通过的提案的值。领导者节点上,序列中的命令是最新的,不再需要通过准备请求来发现之前被大多数节点通过的提案,领导者可以独立指定提案中的值
和重复执行Basic Paxos相比,Multi-Paxos引入领导者节点之后,因为只有领导者节点一个提议者,只有它说了算,所以就不存在提案冲突。另外,当主节点处于稳定状态时,就省掉准备阶段,直接进入接受阶段,所以在很大程度上减少了往返的消息数,提升了性能,降低了延迟
Chubby中通过引入主节点,实现了兰伯特提到的领导者(Leader)节点的特性。也就是说,主节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提交提案冲突的情况了
在Chubby中,主节点是通过执行Basic Paxos算法,进行投票选举产生的,并且在运行过程中,主节点会通过不断续租的方式来延长租期。如果主节点故障了,那么其他的节点又会投票选举出最新的主节点,也就是说主节点是一直存在的,而且是唯一的
在Chubby中实现了兰伯特提到的,当领导者处于稳定状态时,省掉准备状态,直接进入接受阶段这个优化机制
在Chubby中页实现了成员变更,以此保证节点变更的时候集群的平稳运行
最后,在Chubby中为了实现强一致性,读操作也只能在主节点上执行。也就是说,只要数据写入成功,之后所有的客户端督导的数据都是一致的(只能在主节点进行读操作,效果相当于单机,对吞吐量和性能有所影响)
参考:
05 | Paxos算法(一):如何在多个节点间确定某变量的值?
06 | Paxos算法(二):Multi-Paxos不是一个算法,而是统称