MIT 6.824 Lab2A
这门课的关键就是Raft,Lab2 A就能看出相对于MapReduce,需要阅读的材料和理解更加的多,也用到了一些平时开发没怎么注意到的思路。
Raft
Leader选举
实验的开始是实现选举机制,首先需要理解选举的流程。在raft.go
文件中实际上屏蔽了一些底层信息,比如加入Server,维护Server的状态等相关信息,这部分内容实际上是在config.go
文件中的。既然不考虑一些底层的具体实现,只需要考虑Raft的算法本身。
TestInitialElection2A
中创建了3个Server,也就是说1个会成为Leader,其他两个应该是处于Follower的状态。首先每个Server是处于Follower状态,但这时候的Follower并没有follow任何Leader,Follower有一个属于自己的随机timeout,也就是Election Timeout,通常timeout设置为150~300ms。当该timeout结束后,这个Server就会从Follower切换到Candidate状态,同时会开始进入election term。这部分阶段做了一些工作,其中最主要的工作应该算是
拉票
。选举阶段,转为Candidate状态的节点执行了以下几个操作:
- 增加currentTerm
- 给自己投票
- 重置选举计时器
- 发送RequestVote给其他节点
当该节点收到过半的赞成票时,即可从Candidate转为Leader。
RequestVote
这部分内容参考论文 Figure 2 上的部分进行编码即可,这里要注意的是,除了 RequestVote RPC
里提到的规则,所有 Servers 都需要遵循一个规则
If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower
因此 RequestVote
函数可以初步实现。
func (rf *Raft) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply) {
// Your code here (2A, 2B).
rf.mu.Lock()
defer rf.mu.Unlock()
if args.Term < rf.currentTerm {
reply.VoteGranted = false
return
}
if args.Term > rf.currentTerm {
rf.currentTerm = args.Term
rf.state = FOLLOWER
rf.votedFor = args.CandidateId
}
if args.Term == rf.currentTerm {
if rf.votedFor == args.CandidateId || rf.votedFor == -1 {
rf.votedFor = args.CandidateId
reply.VoteGranted = true
rf.elapseReset <- struct{}{}
}
}
reply.Term = rf.currentTerm
}