paxos算法详解以及模拟代码

0 paxos算法解决了什么问题

现在有n个人组成提一个会议,这个会议的目的是为了确定今年的税率,那么每个人都会提出自己认为的今年的合理的税率,为了大家能够达成一致,有了paxos算法。实际里,这个会议就是一个集群。

1 paxos算法详解

1.1 基本概念

    1. 角色:
      提议者(proposer):提议的发起者。
      批准者(acceptor):对提议进行批准。
      学习者(learner):作为一致性协议的副本因子,对被超过半数的 acceptor
      批准的方案进行学习。
    1. 提议(propose):
      Proposer(提议者)可以提出提议,最终要达成一致的 value 就在提议里。Acceptor(接收者)根据提议的编号来选择是否接受(accept)提议。如果超过半数的cceptor 接收了一个提议,那么这个提议就被接受(accepted)了,提议里的 value 也就被选定了。
    1. 仲裁集合(Quorums): 是 Acceptor(假设有 N 个)的一个子集,任何两个 Quorums 至少有一个相同的成员,也就是说一个 quorums 是一个包含了超过 N/2+1 个 Acceptor 的一个集合。
    1. 提议序号(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。有两种情况:
    1. 如果 n 高于接受者从任何提议者接收到的每个先前的提议编号,那么接受者必须向提议者返回一条消息,我们称其为“承诺”,以忽略所有将来的提议数量少的提议比 n。如果接受者在过去某个时候接受了提议者的提议(也就是第二阶段中批准的提议),则在对提议者的答复中必须包含先前接受的的提议编号(例如 m)和相应的接受(批准)值(例如 w)。
    1. 否则(即,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算法的活锁问题

livelock

如上图,(从上图也可以看出集群里的一个机器可以有多重身份)首先 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 
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值