看过太多的paxos的算法的介绍,paxos个人认为没有那么难,但是为啥那么难懂呢?因为大家都是根据理论讨论,作为一个程序员,源码下无秘密,因此我结合keyspace的paxos lease的源码实现来分析一下paxos的算法(paxos的直接实现会存在活锁问题,因此大多数的实现都是通过一个paxos的lease算法选择一个主proposer,可以看成一轮paxos的实现)。
1. 阶段一: prepare-》promise
proposer选择一个提案编号proposalID,然后向acceptor的集合中的全部成员发送编号为proposalID的Prepare请求。
void PLeaseProposer::StartPreparing() { Log_Trace(); // proposer启动定时器Timer1,等待T秒便超时 EventLoop::Reset(&acquireLeaseTimeout); state.proposing = false; state.preparing = true; state.leaseOwner = RCONF->GetNodeID(); state.highestReceivedProposalID = 0; state.proposalID = RCONF->NextHighest(highestProposalID); if (state.proposalID > highestProposalID) highestProposalID = state.proposalID; msg.PrepareRequest(RCONF->GetNodeID(), state.proposalID, RLOG->GetPaxosID()); // proposer启动定时器Timer1,等待T秒便超时 BroadcastMessage(); }
acceptor接收到一个编号为proposalID的Prepare请求,且编号proposalID大于该acceptor已经响应的所有Prepare请求的编号,那么它就会将它已经批准过的最大编号的提案作为响应反馈给Proposer,同时该Acceptor会承诺不会再批准任何编号小于proposalID的提案。
void PLeaseAcceptor::OnPrepareRequest() { Log_Trace("msg.paxosID: %" PRIu64 ", my.paxosID: %" PRIu64 "", msg.paxosID, RLOG->GetPaxosID()); if (msg.paxosID < RLOG->GetPaxosID() && (int) msg.nodeID != RLOG->GetMaster()) return; // only up-to-date nodes can become masters RLOG->OnPaxosLeaseMsg(msg.paxosID, msg.nodeID); unsigned senderID = msg.nodeID; if (state.accepted && state.acceptedExpireTime < Now()) { EventLoop::Remove(&leaseTimeout); OnLeaseTimeout(); } // 失败: 如果msg.ballot_number < local.promisedBallotNumber,则发送拒绝消息 if (msg.proposalID < state.promisedProposalID) msg.PrepareRejected(RCONF->GetNodeID(), msg.proposalID); else { // 成功: 否则,发送accept,包含的内容已经promise的最大编号和T state.promisedProposalID = msg.proposalID; if (!state.accepted) msg.PrepareCurrentlyOpen(RCONF->GetNodeID(), msg.proposalID); else // 返回已经被accept的结果 msg.PreparePreviouslyAccepted(RCONF->GetNodeID(), msg.proposalID, state.acceptedProposalID, state.acceptedLeaseOwner, state.acceptedDuration); } SendReply(senderID); }
接下来proposer根据acceptor的响应,决定是否开始阶段二
// 阶段1的Proposer请求后的相应结果处理: prepare的处理 void PLeaseProposer::OnPrepareResponse() { Log_Trace(); if (!state.preparing || msg.proposalID != state.proposalID) return; numReceived++; if (msg.type == PLEASE_PREPARE_REJECTED) // (1)被拒绝 numRejected++; else if (msg.type == PLEASE_PREPARE_PREVIOUSLY_ACCEPTED && msg.acceptedProposalID >= state.highestReceivedProposalID) { // (2) 已经有结果了 state.highestReceivedProposalID = msg.acceptedProposalID; state.leaseOwner = msg.leaseOwner; } //失败: prepare的结果被拒绝, 否则,随机等待一段时间,提高编号重启prepare过程 if (numRejected >= ceil((double)(RCONF->GetNumNodes()) / 2)) { StartPreparing(); return; } // 成功: 如果多数派accept,则进入promise阶段 // see if we have enough positive replies to advance if ((numReceived - numRejected) >= RCONF->MinMajority()) StartProposing(); }
2. 阶段二: propose-》accept
如果Propser收到来自半数以上的Acceptor对于其发出的编号为proposalID的Prepare请求的响应,那么它就会发送一个针对[proposalID, V]提案的Accept请求给Acceptor。 注意:这里V的值就是收到的响应中的提案的值(后者认同前者原则,如果已经生成提案,会保持与前面一致性),如果还没有任何提案,那么它就是任意值(注意,在keyspace就是proposer对应的节点)。
void PLeaseProposer::StartProposing() { Log_Trace(); state.preparing = false; // 如果prepare阶段接收的value不为空,则终止promise if (state.leaseOwner != RCONF->GetNodeID()) return; // no point in getting someone else a lease, // wait for OnAcquireLeaseTimeout // 否则,发送(ballot number,proposer id ,T) state.proposing = true; state.duration = MAX_LEASE_TIME; state.expireTime = Now() + state.duration; msg.ProposeRequest(RCONF->GetNodeID(), state.proposalID, state.leaseOwner, state.duration); BroadcastMessage(); }
acceptor接收到针对[proposalID,V]的Accept请求,只要该Acceptor尚未对编号大于proposalID的Prepare请求做出响应,它就可以通过这个提案。
void PLeaseAcceptor::OnProposeRequest() { Log_Trace(); unsigned senderID = msg.nodeID; if (state.accepted && state.acceptedExpireTime < Now()) { EventLoop::Remove(&leaseTimeout); OnLeaseTimeout(); } // 失败: 提交结果时,仍然检查编号 if (msg.proposalID < state.promisedProposalID) msg.ProposeRejected(RCONF->GetNodeID(), msg.proposalID); else { // 成功 state.accepted = true; state.acceptedProposalID = msg.proposalID; state.acceptedLeaseOwner = msg.leaseOwner; state.acceptedDuration = msg.duration; state.acceptedExpireTime = Now() + state.acceptedDuration; leaseTimeout.Set(state.acceptedExpireTime); EventLoop::Reset(&leaseTimeout); msg.ProposeAccepted(RCONF->GetNodeID(), msg.proposalID); } SendReply(senderID); }
当proposer接收到半数以上的accept通过响应后,则提案最终通过。
void PLeaseProposer::OnProposeResponse() { Log_Trace(); if (state.expireTime < Now()) { Log_Trace("already expired, wait for timer"); return; // already expired, wait for timer } if (!state.proposing || msg.proposalID != state.proposalID) { Log_Trace("not my proposal"); return; } numReceived++; if (msg.type == PLEASE_PROPOSE_ACCEPTED) numAccepted++; Log_Trace("numAccepted: %d", numAccepted); // 成功: see if we have enough positive replies to advance if (numAccepted >= RCONF->MinMajority() && state.expireTime - Now() > 500 /*msec*/) { // 被多数派接收 // a majority have accepted our proposal, we have consensus state.proposing = false; msg.LearnChosen(RCONF->GetNodeID(), state.leaseOwner, state.expireTime - Now(), state.expireTime); EventLoop::Remove(&acquireLeaseTimeout); extendLeaseTimeout.Set(Now() + (state.expireTime - Now()) / 7); EventLoop::Reset(&extendLeaseTimeout); BroadcastMessage(); return; } // 失败: 否则, 重新开始prepare if (numReceived == RCONF->GetNumNodes()) StartPreparing(); }
相关推荐
深入理解Paxos源码有助于我们掌握其实现细节,以及如何在实际项目中应用一致性算法。通过阅读和分析`libpaxos`,我们可以学习如何处理网络延迟、节点故障以及如何确保在分布式环境中的一致性。这对于我们设计和实现...
总的来说,这个C++实现的Paxos算法项目为学习和研究Paxos提供了一个实践平台,对于理解分布式系统的一致性协议有着重要的价值。无论是学术研究还是实际开发,都能从中受益。通过动手操作和调试代码,我们可以更好地...
很不错的paxos算法分析文档,值得一看,虽不能深入研究,但是可以初步了解!
通过源码分析,读者还能更深入地了解Zookeeper的内部实现机制,这对于开发和调试分布式系统来说是非常宝贵的。 总之,《从Paxos到Zookeeper:分布式一致性原理与实践》是一本全面而实用的教材,无论你是初学者还是...
java笔初级试题基本的Paxos 汤姆·科卡涅 <> v2.0,2013 年 1 月 介绍性说明 这个存储库包含我第一次尝试提供有用且具有教育意义的 ...这个实现是专门为促进理解基本的 Paxos 算法以及在实际使用
Paxakos 是基于 Leslie Lamport 的Paxos的分布式共识算法的纯 Rust 实现。它使分布式系统能够一致地修改其网络中的共享状态,即使在出现故障的情况下也是如此 为了使用 Paxakos,需要实现特征 [ LogEntry]、[ State...
Paxos算法深入分析.doc
- **Multi-Paxos**:简化Paxos的实现,通过复用同一编号的提案,避免了每次决策都需要多轮通信的问题。 - **Fast Paxos**:在多数派节点已经就一个值达成一致的情况下,可以快速达成决策,减少了通信次数。 - **Raft...
在Paxos算法的多线程实现中,通常会为每个节点(如Acceptor、Proposer或Learner)创建独立的线程,以模拟它们并行执行的行为。这样可以提高系统的处理能力,但同时也增加了线程安全的挑战。 1. **Proposer线程**:...
- `paxos-core`模块可能包含了Paxos协议的核心实现,包括Proposal、Acceptance和Learn等消息类型,以及ProposalActor、AcceptorActor和LearnerActor的定义。 - `paxos-cluster`模块可能用于处理集群间的通信和协调,...
OpenReplica作为Paxos算法的一种开源实现,通过其独特的面向对象设计和多返回机制,为分布式系统提供了一种强大的复制和同步解决方案。它的出现不仅降低了分布式系统开发的复杂性,还提高了系统的弹性和可扩展性。...
在源码中,你可以看到如何实现Paxos协议的提案者、接受者和学习者角色,以及它们之间的交互逻辑,这将有助于深入理解协议的工作机制。 Zookeeper是Apache的一个开源项目,它基于Paxos等一致性算法,为分布式应用...
本书对Paxos和ZooKeeper的源码进行了详尽的分析,这对于希望提高分布式系统开发实战能力的开发者来说尤为宝贵。通过分析源码,读者可以了解状态机的实现、消息传递的机制、故障恢复的处理等核心内容,这些都是构建...
Raft算法更易于理解和实现,它将Paxos算法分解为几个可管理的子问题,但仍然能够提供与Paxos相似的容错能力。Raft算法强调的是对领导者(Leader)的选举和日志复制,它简化了节点间的状态转换和通信流程,从而降低了...
Paxos算法实际上描述了如何将一系列操作顺序地应用到状态机上,以实现系统的一致性。 Paxos算法的适用性和研究: Paxos算法在工业界有着广泛的应用,例如在Google的Chubby分布式锁服务、Apache ZooKeeper等系统中都...
这篇名为"cheap-paxos.pdf"的论文深入探讨了Paxos算法的一个变种——廉价Paxos(Cheap Paxos),它在保持Paxos算法基本性质的同时,优化了性能,降低了复杂性,尤其适用于大规模分布式系统。 Paxos算法最初由Leslie...
这本书籍深入剖析了Zookeeper的内部工作机制,包括数据模型(ZNode)、事务日志、快照、Watcher机制等,同时提供了源码分析,帮助读者理解其背后的实现细节。通过阅读本书,读者可以掌握如何在实际项目中利用...
《从PAXOS到ZOOKEEPER分布式一致性原理与实践...通过阅读这本书和分析源码,你不仅可以深化对PAXOS和ZOOKEEPER的理解,还能提升自己在分布式系统开发和设计方面的能力,为构建大规模、高可用的分布式应用打下坚实基础。
### 分布式共识问题与Paxos算法 分布式共识问题是分布式系统领域的一个核心问题,它要求一组进程能够就某一个值...通过这些改进和实施考量,Fast Paxos旨在为大规模分布式系统提供一个更加高效、可靠的共识解决方案。