mit6.824 lab2a-raft选举

初步实现raft选举,保证一个任期仅有一个leader,在leader宕机后其他follower会自动拉票竞选成为leader。

大致思路

  1. 最初所有服务器都为follower,并且初始化一个选举计时器(300~400ms)。当选举计时器超时,follower会成为candidate进行竞选投票,如果candidate得到大部分的选票,则会成为leader
  2. leader会定期发送心跳包以及重置自己的选举计时器,防止新的一轮选举在自己未宕机的情况下开始。

RPC部分

//请求投票:候选者想要成为leader
func (rf *Raft) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply)
//复制log 或 心跳包(log为空时为心跳包)
func (rf *Raft) AppendEntries(args *AppendEntriesArgs, reply *AppendEntriesReply)

注意:rpc会被多个服务器调用,需要全程加锁

服务器接收到任何任期高于自己的rpc后,会更新自己的任期。

RequestVote:

1.向当前服务器请求投票,如果candidate的任期<当前服务器的任期,则会拒绝投票。
2.在收到投票请求后,自身转变为follower,并且重置自己的选举超时时间。
3.如果candidate的任期合法并且leader在最新任期没有进行投票,则投票给candidate。

AppendEntries:

1.若leader任期<当前服务器任期,则直接返回
2.服务器在接收到心跳包时,会转变成follower,并且重置自己的选举计时器。

实现细节

  • 成为候选人:1.增加term 2.选举自己 3.重置选举计时器 4.并行发送投票请求
  • 并行向其他服务器请求投票:
for i := 0; i < len(rf.peers); i++ {
    
    
				reply := RequestVoteReply{
    
    0, false}
				if i != rf.me {
    
    
					go func(i int, args RequestVoteArgs, reply RequestVoteReply, rf *Raft) {
    
    
						if rf.status == "candidate" {
    
    
							rf.sendRequestVote(i, &args, &reply) //发送请求投票rpc
						}
						if reply.VoteGranted == true {
    
    
							//获得投票
							rf.SuccessVoteNum++
						} else {
    
    
							//未获取投票
						}
						ch <- reply 
						finishVoteNum++
					}(i, args, reply, rf)
				}
			}
			//完成全部投票或者得到的投票数过半时停止等待
			for {
    
    
				select {
    
    
				case <-ch:
					if finishVoteNum == len(rf.peers)-1 || rf.SuccessVoteNum > len(rf.peers)/2 {
    
    
						goto checkTerm //这里只有goto+标签和break+标签能够退出
					}
				}
			}

		checkTerm:

猜你喜欢

转载自blog.csdn.net/weixin_44866921/article/details/129354797