0 paxos算法解决了什么问题
现在有n个人组成提一个会议,这个会议的目的是为了确定今年的税率,那么每个人都会提出自己认为的今年的合理的税率,为了大家能够达成一致,有了paxos算法。实际里,这个会议就是一个集群。
1 paxos算法详解
1.1 基本概念
-
- 角色:
提议者(proposer):提议的发起者。
批准者(acceptor):对提议进行批准。
学习者(learner):作为一致性协议的副本因子,对被超过半数的 acceptor
批准的方案进行学习。
- 角色:
-
- 提议(propose):
Proposer(提议者)可以提出提议,最终要达成一致的 value 就在提议里。Acceptor(接收者)根据提议的编号来选择是否接受(accept)提议。如果超过半数的cceptor 接收了一个提议,那么这个提议就被接受(accepted)了,提议里的 value 也就被选定了。
- 提议(propose):
-
- 仲裁集合(Quorums): 是 Acceptor(假设有 N 个)的一个子集,任何两个 Quorums 至少有一个相同的成员,也就是说一个 quorums 是一个包含了超过 N/2+1 个 Acceptor 的一个集合。
-
- 提议序号(Proposal number)和批准值(agreed value):对于任意一个给定的提议者,其给定的提议对应的提议号必定全局唯一。每一个提议(n,v 代表的话)都有一个提议序号(n)和其想要通过的提议值(v),为了便于理解,设想一个权力机关去决定今年的税率,那么每个人会给自己的提议有一个全局唯一的序号(n),然后还包含对于想要决定的目标变量(税率)的值(n)也就是税率的大小。
1.2 算法具体流程
Paxos(这里主要说的是 Basic paxos 算法)的具体流程分为两阶段:
Phase1
- (1) Phase 1a - proposer 准备(Prepare):
Proposer 创建一个条消息,我们将其称为“Prepare”,以数字 n 标识。请注意,n 不是要提议的值也不是可能会被同意的商定的值,而只是一个数字,该数字由提议者唯一标识此初始消息(发送给接收者)。数字 n 必须大于此提议者在先前的任何 Prepare 消息中使用的任何数字。然后,它将包含 n 的 Prepare消息发送到接受方的一个仲裁集合(超过一半以上的 Acceptor 的集合)。请注意,Prepare 消息仅包含数字 n(也就是说,它不必包含例如建议的值,通常用 v 表示)。提议者决定谁在仲裁集合。如果提议者不能与至少一个接受者的仲裁集合进行通信,则他不应启动 Paxos。 - (2) Phase 1b - acceptor 承诺(Promise):
任何接受者都在等待来自任何提议者的准备消息。如果接受方收到一条准备消息,则接受方必须查看刚刚收到的准备消息的标识符编号 n。有两种情况: -
- 如果 n 高于接受者从任何提议者接收到的每个先前的提议编号,那么接受者必须向提议者返回一条消息,我们称其为“承诺”,以忽略所有将来的提议数量少的提议比 n。如果接受者在过去某个时候接受了提议者的提议(也就是第二阶段中批准的提议),则在对提议者的答复中必须包含先前接受的的提议编号(例如 m)和相应的接受(批准)值(例如 w)。
-
- 否则(即,n 小于或等于接受者从任何提议者收到的任何先前提议编号),接受者可以忽略收到的提议。在这种情况下,Paxos 不必工作。但是,为了优化起见,发送拒绝(Nack)响应将告诉提议者它停止以 n 作为提议的序号去建立共识(这是优化手段,因为即使不主动告诉,其提议的序号也会增长)。
Phase2
- (1) Phase 2a - proposer 发送 Accept 消息:
- 1 如果提议者从接受者的一个仲裁集合中获得大部分承诺,则需要为其提议设置值 v。
- 2 如果任何接受者先前已接受过一个提议,那么他们会将这个提议发送给提议者,提议者现在必须将其提议值 v 设置为与接受者报告的(与这些接受者最高提议编号关联的)提议值(也就是提议者之前接受过的提议),我们称之为 z。
- 3 如果到目前为止,没有一个接受者接受提议,则提
议者可以选择其最初想要提议的值,例如 x。在这个阶段,提议者会发送一个 Accept 信息:(n,v)给一个接受者个仲裁集合。(n 就是之前提议者发给接受者的准备信息里的提议里的提议序号。v=z 或 者 v=x (当所有接受者都没有接受过提议时。)),这个 accept 请求可以理解为一个请求:“请接受这个提议!”。
- (2) Phase 2b - acceptor 发送 Accepted 消息:
如果接受者从提议者接收到 Accept 信息(n,v),分为两种情况:- 1 如果:它尚未承诺(在 Paxos 协议的阶段 1b 中)仅考虑提议序号大于 n 的提议时,则它应该将(刚接收到的 Accept 消息的)值 v 注册为(协议)的接受值,并向提议者和每个学习者(通常是提议者本身)发送一条接受消息。
- 2 否则:它可以忽略这个 Accept 消息。
1.3 paxos算法的活锁问题

如上图,(从上图也可以看出集群里的一个机器可以有多重身份)首先 s1-3 给出 3 个 preparemeesage,然后 s1-3 是一个 quorum 得到了大多数支持,开始发送 phase2-a 的 accept 信息(A3.1),但是由于在发送phase2-a 的 accept 消息之前,s3-5 给出 3 个 prepare message,s3 又更新了自己主张的提议,那么之前发送的(accept 信息)A3.1 就不会被回应,之后 s1-2 发现由于超过半数(s3-5)拒绝了自己,然后就出了新的一轮 prepare message 为 P4.1,
然后,就这样循环往复下去出现了活锁。
其改进方法:
- 解决方案1:出现冲突的时候,在重新开始执行prepare message流程之前,施加随机的延迟;让其他proposers有机会完成value的确认
- 解决方案2:multi-paxos会使用leader来避免活锁;
2 paxos算法实现
2.1 paxos.cpp
模拟paxos算法的主要流程
#include <stdlib.h>
#include <stdio.h>
#include "Paxos/Acceptor.h"
#include "Paxos/Proposer.h"
#include "lib/Thread.h"
#include "lib/Lock.h"
#include "lib/mapi.h"
#include "lib/atom.h"
#include "lib/Logger.h"
paxos::Proposer p[5];
paxos::Acceptor a[11];
mdk::Mutex l[11];
int finishedCount = 0;
int finalValue = -1;
bool isFinished = false;
mdk::uint64 g_start;
mdk::Logger g_log;
void* Proposer(void *id)
{
mdk::Logger log;
char logName[256];
sprintf( logName, "Proposer%d", (long)id );
log.SetLogName(logName);
log.SetMaxLogSize(10);
log.SetMaxExistDay(30);
log.SetPrintLog(false);
paxos::Proposer &proposer = p[(long)id];
paxos::PROPOSAL value = proposer.GetProposal();
paxos::PROPOSAL lastValue;
int acceptorId[11];
int count = 0;
mdk::uint64 start = mdk::MillTime();
while ( true )
{
value = proposer.GetProposal();//拿到提议
log.Info("Info", "Proposer%d号开始(Propose阶段):提议=[编号:%d,提议:%d]\n",
(long)id, value.serialNum, value.value);
count = 0;
int i

最低0.47元/天 解锁文章
858

被折叠的 条评论
为什么被折叠?



