当前位置: 首页 > 科技观察

实现分布式Kv-2RaftLeader选举

时间:2023-03-15 18:56:17 科技观察

从本文开始,我们将基于raft构建分布式kv。Raft是一种分布式共识算法,主要保证分布式系统中各个节点的数据一致性。raft算法比较复杂,因为它解决的分布式一致性问题本来就是一个难题。raft算法的实现可以分为三个部分:Leader选举日志复制安全如果对raft算法不熟悉,可以看看这个网站的动画展示:http://thesecretlivesofdata.com/raft非常形象地展示了raft算法面临的问题以及raft算法解决问题的基本过程。当然raft算法的论文也很值得参考:https://github.com/maemual/raft-zh_cn我在网上也找到了一个不错的raft算法系列文章:https://www.raft-zh_cncodedump.info/post/20180921-rafthttps://blog.betacat.io/post/raft-implementation-in-etcd看完这些资料,你应该对raft算法有了一个大概的了解,然后你就可以看到如何实施它。本文暂时只介绍第一个Leader选举问题,对应TinyKV中的Project2aa部分。在raft集群中,节点分为三种状态:Follower(追随者)、Candidate(候选者)、Leader(领导者)。节点的初始状态是Follower。Follower节点需要周期性的获取Leader的心跳信息来维护自己的状态。Follower节点有一个超时时间(ElectionTimeout)。在此期间,如果没有收到Leader的心跳信息,就会认为集群中没有Leader,然后发起选举。选举的具体过程:如上图所示,节点A的ElectionTimeout先到,于是将自己的状态变为Candidate,并将任期号Term加1(图中初始任期号为0,加1后变为1),然后给自己投票,向B和C两个节点发送requesttovote消息。节点B和C发现自己的任期数小于A的任期数,因此将投票给A。节点A收到回复后,计算投票是否超过节点数的一半,如果满足,则将成为领导者。以上是Leader选举的理想情况。严格来说,候选人节点启动选举后,它需要维持国家,直到以下情况发生:它本身赢得了选举。其他节点赢得了选举。Leader的第一个case就是上面说的选举过程。自己发起选举,获得半数以上节点的选票,成为Leader。Inthesecondcase,ifduringtheelectionprocess,othernodesbecomecandidatesandwintheelection,thenitreceivestheAppendEntryRPCmessagefromthenewLeader,andifthetermnumberofthenewLeaderisgreaterthanitsown,thenItwill认为Leader有效,将自己变为Follower。第三种情况对应节点在选举中既没有输也没有赢。如果集群中有偶数个节点,两个节点同时发起选举,就有可能出现这种情况。在这种情况下,选举将无效。.Whentheelectiontimeoutcomesagain,ifthereisstillnonewLeader,theCandidatewillinitiateanewroundofelections.说到代码实现,首先,初始逻辑在tick函数中,会被外层调用。我们需要判断该节点的选举超时时间是否超时,如果超时,则需要发起选举。//tick通过asingletick.func(r*Raft)tick(){//YourCodeHere(2A).switchr.State{caseStateLeader://...caseStateFollower,StateCandidate:r.electionElapsed++ifr.electionElapsed>=r.electionTimeout{//发起新的选举r.startElection()}}}发起选举,将自己改为Candidate,任期号+1,为自己投票。然后需要向其他节点发送MsgRequestVote类型的消息。MsgRequestVote消息中需要包含当前节点最后一条日志的Index和Term,以便Follower判断该节点的日志是否是最新的。其他Follower节点收到MsgRequestVote消息后开始处理,处理时需要注意几点:如果msg的Term小于自己的Term,直接拒绝该消息;如果msg的Term比自己的大,需要改成Follower(如果不是Follower),更新Term需要查看msg的term号和索引号。如果msg的日志不是最新的,则拒绝该消息。所有验证通过后,Follower节点将投赞成票,并向Candidate节点发送MsgRequestVoteResponse消息。Candidate节点收到MsgRequestVoteResponse消息后,需要记录投票结果,然后计算投票是否满足:如果拒绝投票超过节点数的1/2,则选举失败,Candidate节点成为Follower状态;如果赞成票数超过节点数的1/2,则选举成功。如果选举成功,需要将自己的状态变为Leader,然后向其他节点发送一个空数据Entry的MsgAppend消息,以防止其他节点继续发起选举。附言。具体代码实现请参考etcd的raft,然后在此基础上手动实现TinyKV中的代码。