分布式__Paxos分布式一致性协议的基本原理
一、什么是Paxos
Paxos是一种算法,用于在一组通过异步网络通信的分布式设备之间达成共识。一个或多个客户端向Paxos提出一个值,当大多数(一半以上)运行Paxos的设备同意其中一个提议的value时,我们就达成了共识(Consensus)。Paxos被广泛使用,因为它是第一个被严格证明为正确的共识算法。
二、Paxos的基本角色
1)提议者Proposer:从客户端接收请求(值),然后尝试让接受者接收提议的这些值。
2)接受者:Acceptor:接收提议者提出的特定值,并且让当前提议者知道本设备此前已经接受了什么值。一次接受者的回应代表了针对特定提议值的一次投票。
3)学习者Learner:接收共识的结果。
三、Paxos的基本流程
Paxos是一个2阶段协议,意味着提议者需要和接受者交互两次。
从上层来看:
阶段一:提议者向网络中每一个接受者确认它们是否已经接收过提议,如果没有,则提议一个值。
阶段二:如果一半以上接受者都同意这个值,那么则达成共识。
从过程来看:
阶段一:PREPARE-PROMISE
当一个提议者从一个客户端收到针对一个VALUE的共识请求,它会创建一个唯一的提议ID,然后向一半以上的接受者发送一个PREPARE(ID)消息。
每一个接受者根据收到的PREPARE消息查看其ID然后做决定:
Is this ID bigger than any round I have previously received?
If yes
store the ID number, max_id = ID
respond with a PROMISE message
If no
do not respond (or respond with a "fail" message)
如果提议者收到来自大多数接受者的PROMISE响应,它现在知道他们中的大多数愿意参与这个提议。提议者现在可以继续达成共识。这些接受者中的每一个都承诺没有其他数量较少的提案可以达成共识。
阶段二: PROPOSE-ACCEPT
如果提议者收到来自大多数接受者的PROMISE消息,它现在必须告诉接受者接受该提议。如果没有,则必须从另一轮 Paxos 重新开始。
在协议的这个阶段,提议者告诉所有接受者(活着的)接受什么值。它发送:
PROPOSE(ID, VALUE)
每个接受者现在决定是否接受该提案。如果提案的 ID 号仍然是它所见过的最大的,则它接受该提案。回想一下,接受者承诺不接受来自具有较小编号的PREPARE 消息的提议,但可以并且将接受具有较大编号的提议。接受者使用的逻辑是:
is the ID the largest I have seen so far, max_id == N?
if yes
reply with an ACCEPTED message & send ACCEPTED(ID, VALUE) to all learners
if no
do not respond (or respond with a "fail" message)
ACCEPTED 消息可以发送回提议者和学习者,以便他们可以将值传播到任何需要其操作的地方(例如,附加到日志、修改复制的数据库等)。当提议者或学习者收到大多数接受消息时,它就知道已经就该值达成了共识。
总而言之,在第一阶段,提议者发现没有对编号更高的提议做出任何承诺。在第二阶段,提议者要求接受者接受具有特定值的提议。只要在此期间没有更高编号的提案到达,接受者就会回复提案已被接受。
总览:
阶段 1a:Proposer (PREPARE)
提议者发起一条PREPARE消息,选择一个唯一的、不断增加的值。
ID = cnt++;
send PREPARE(ID)
阶段 1b:Acceptor (PROMISE)
一个接受者收到一条PREPARE(ID)消息:
if (ID <= max_id)
do not respond (or respond with a "fail" message)
else
max_id = ID // save highest ID we've seen so far
if (proposal_accepted == true) // was a proposal already accepted?
respond: PROMISE(ID, accepted_ID, accepted_VALUE)
else
respond: PROMISE(ID)
阶段 2a:Proposer (PROPOSE)
提议者现在检查它是否可以使用它的提议,或者它是否必须使用它从所有响应中收到的最高编号的提议:
did I receive PROMISE responses from a majority of acceptors?
if yes
do any responses contain accepted values (from other proposals)?
if yes
val = accepted_VALUE // value from PROMISE message with the highest accepted ID
if no
val = VALUE // we can use our proposed value
send PROPOSE(ID, val) to at least a majority of acceptors
阶段 2b:Acceptor (ACCEPT)
每个接受者都会收到来自提议者的 PROPOSE(ID, VALUE) 消息。如果 ID 是它已处理的最大数字,则接受提议并将该值传播给提议者和所有学习者。
if (ID == max_id) // is the ID the largest I have seen so far?
proposal_accepted = true // note that we accepted a proposal
accepted_ID = ID // save the accepted proposal number
accepted_VALUE = VALUE // save the accepted proposal data
respond: ACCEPTED(ID, VALUE) to the proposer and all learners
else
do not respond (or respond with a "fail" message)
如果大多数接受者接受 ID, value 则达成共识。共识是关于value的,不一定是 ID。
四、异常情况
接受者在第 1 阶段失败
假设一个接受者在阶段 1 失败。这意味着它不会返回PROMISE消息。只要提议者仍然得到大多数接受者的回应,协议就可以继续取得进展。
接受者在第 2 阶段失败
假设一个接受者在第 2 阶段失败。这意味着它将无法发回ACCEPTED消息。只要有足够多的接受者还活着并且会做出响应,这样提议者或学习者会收到来自大多数接受者的响应,这也不是问题。
提议者在准备阶段失败
如果提议者在发送任何消息之前失败,那么它就像根本没有运行一样。
如果提议者在发送一个或多个 PREPARE 消息后失败怎么办?
接受者会发回 PROMISE 响应,但不会跟随 ACCEPT 消息,因此不会达成共识。其他一些节点最终将运行其 Paxos 版本并作为提议者运行,选择自己的 ID。如果较高的 ID 号有效,则算法运行。否则,提议者的请求将被拒绝,并且必须选择更高的 ID 号。
当至少发送了一条 ACCEPT 消息的时候,提议者在 ACCEPT 阶段失败了怎么办?
另一个节点提出了一条带有 PREPARE(higher-ID) 的新消息。接受者的回应是告诉提议者早先的提议已经被接受:
PROMISE(higher-ID, <old_ID, Value>)
如果提议者获得任何带有值的 PROMISE 响应,那么它必须选择具有最高接受 ID 的响应并更改其自己的值。它发出:
ACCEPT(higher-ID, Value)
如果提议者在 ACCEPT 阶段失败,任何接管的提议者都会完成传播被接受的旧值的工作。
假设大多数接受者收到针对某个 ID 的 PREPARE 消息,然后是 PROPOSE 消息。这意味着大多数接受者接受了该 ID。现在大多数人都不能接受具有较低 ID 的 PREPARE 消息。要做到这一点,需要对编号较低的 ID 进行大部分承诺,但我们已经对编号较高的 ID 做出了承诺。具有更高 ID 和不同值的PROPOSE 消息也不会被大多数人接受。至少有一个接受者会知道它接受的 ID 和相应的值,它将传播回提议者。您可以拥有更高 ID 的提案,但提案人有义务为它们提供相同的值。如果提议者发送:
PREPARE(high-ID)
至少有一个接受者会用之前接受的 ID 和值来回应:
PROMISE(high-ID, accepted-ID, value)
提议者必须返回一个PROPOSE(high-ID, value)。这就是提议者和学习者如何了解被接受的内容并最终创造多数共识结果的方式。
提议者在 ACCEPT 阶段失败
在这里,接管的提议者不知道它正在接管未决的共识。它只是提出了一个值,但没有意识到共识协议已经在进行中。这里有两种情况需要考虑:
1) 提议者不会从大多数包含旧提议 ID 和相应值的接受者那里得到任何响应。这意味着尚未达成多数同意。然后提议者只是正常执行并完成其协议。
2) 接管的提议者知道它正在接管一个未决的共识,因为它至少得到一个包含已接受的提议和值的响应。它只是使用先前的值执行并完成协议。