什么是实例?
Paxos 中的命名法有点不直观。
- 实例是选择一个值的算法。
- 一轮是指提议者对 Phase 1 + Phase 2 的单次尝试。一个节点在Paxos实例中可以有多个轮。在所有节点中,每个实例的轮 ID 都是全局唯一的。这有时称为提案编号。
- 一个节点可以承担多个角色;最值得注意的是提议者和接受者。在我的回答中,我假设每个节点都承担两个角色。
- 阶段 1 也称为准备阶段。
- 在阶段 1a 中,Proposer 向 Acceptors 发送 Prepare!(roundId) 消息
- 在阶段 1b,Acceptors 回复 Promise!(roundId, value) 或 PrepareNack!()
- 阶段 2 也称为接受阶段。
- 在阶段 2a 中,Proposer 向 Acceptor 发送 Accept!(roundId, value) 消息
- 在阶段 2b 中,Acceptor 回复 Accepted!(...) 或 AcceptNack!()
假设一个集群分为 3 个区域,每个区域包含 3 个节点(总共 = 9 个节点)。如果区域之间的通信中断会发生什么?任何领导者都无法达到法定人数(即 5)。
Paxos 要求您至少可以获得一个仲裁(在您的情况下为 5 个节点)。使用您的三个区域的解决方案;在三个区域之间有两个网络分区是非常坏的消息。我还使用了一种 Paxos 版本,它可以将节点成员身份从一个实例更改为下一个实例。这对于分区和节点故障很有用。
Paxos不是要进入死循环了吗?
Paxos 的幼稚实现不能保证终止,因为多个节点可以跨越准备阶段。有两种方法可以解决这个问题。一种是在开始新的准备阶段之前进行随机退避。第二个是将所有请求路由到指定的领导者,该领导者充当提议者(领导者由 Paxos 实例选择。另见 Multi-paxos)
在阶段 1b:“如果提案编号 N 大于任何先前的提案,则每个 >>Acceptor 承诺不接受小于 N 的提案,并将它最后接受的值发送给 >>this instance to the Proposer”。
“它接受的最后一个值”是什么?提案人之前是否有任何提案编号?
当一个节点收到来自 Proposer 的 Accept!(roundId, value) 消息并且它没有承诺不接受该值(由于 Prepare!(higherRoundId) 消息)时,它会存储该值和 roundId(我会打电话给他们acceptedValue
和acceptedRoundId
)。由于随后的 Accept!(...) 消息,它可能会覆盖这些。
当节点收到来自 Proposer 的 Prepare!(roundId) 消息时,它将 roundId 存储为promiseRoundId = max(roundId, promiseRoundId)
. 然后它向 Proposer 发送一个Promise!(acceptedRoundId, acceptedValue)
回复。注意:如果节点没有收到 Accept!(...) 消息,它会回复Promise!(null, null)
.
在阶段 1a:是否包含与 Prepare 消息达成一致的值,还是推迟到 Accept!信息?或者这很重要?
没有必要发送它。我不。
在阶段 2a 中:“如果任何 Acceptor 已经接受了一个值,则领导者必须选择一个具有最大提案编号 N 的值”。
这里的价值是什么?是提案号吗?我不相信,但这句话不清楚。
该值是算法达成共识的实际数据。我会改写为
要开始接受阶段,提议者必须根据准备阶段的结果选择要接受的值。如果任何 Acceptor 回复了 Promise(roundId, value),Proposer 必须使用与最高 roundId 关联的值。否则,Proposer 只收到 Promise(null, null),并且可以选择任何值发送给接受者。
注意:这里的提案号和roundId是一样的。
在阶段 2a:“否则,Proposer 可以自由选择任何值”。这是什么意思?有什么价值?对于提案编号?
这是你想要达成共识的价值。这通常是跨分布式系统的状态更改,可能由客户端请求触发。
Paxos 似乎依赖于不断增加的 N(提案编号)值来工作?这个对吗?
维基百科条目没有讨论节点在开始参与 Paxos 之前应该设置的初始值。这些是什么?
Round ids(又名提案编号)应该增加,并且每个实例在所有节点上必须是唯一的。Paxos 论文假设您可以做到这一点,因为它很容易实现。这是一种在所有节点上产生相同结果的方案:
- 假设有 M 个节点参与一个 Paxos 实例。
- 按字典顺序对所有节点进行排序。index[node] 是此排序列表中节点的索引。
roundId = i*M + index[node]
其中 i 是该节点开始的第 i 轮(即 i 在每个 paxos 实例的每个节点中是唯一的,并且是单调递增的)。
或者在伪代码中(显然缺少一些主要优化):
define runPaxos( allNodesThisPaxosInstance, myValue ) {
allNodesThisPaxosInstance.sort()
offset = allNodesThisPaxosInstance.indexOf( thisNode )
for (i = 0; true; i++) {
roundId = offset + i * allNodesThisPaxosInstance.size()
prepareResult = doPreparePhase( roundId )
if (!prepareResult.shouldContinue?)
return
if (prepareResult.hasAnyValue?)
chosenValue = prepareResult.valueWithHighestRoundId
else
chosenValue = myValue
acceptResult = doAcceptPhase( roundId, chosenValue )
if (!acceptResult.shouldContinue?)
return
}
}