前言
做2020的MIT6.824,刚刚开始了第二个实验,是Raft 2A,这个实验是实现不带log的leader election以及heartbeat,花了很多时间在理解paper上面,然后花了很多时间在debug上面。这个实验如果理解了Raft要干什么的话,难点就是避免deadlock。下面有几个链接对我的实验很有帮助,可以参考
##每5个test并行运行,运行100次2A的test
sh test_many.sh 100 5 2A
一、Raft
流程
我是看着动画流程实现的,这个很有助于理解
动画流程
我实现的大概流程
- Make: 初始化一个Raft,然后在return前用另外一个go程做LeaderElection以及监控当前的state
- LeaderElection:设置一个timmer,超时kickoffElection
- kickoffElection: 向每个peer发送sendRequestVote的rpc
3.1. 如果收到小于大多数的票,return
3.2. 如果收到多数票,convertToLeader并且SendHeartbeat - SendHeartbeat: 向每个peer发送sendAppendEntries
4.1. 如果reply.Success不为true: convertToFollower
4.2. 其他情况直接return
struct
我基本就是对着Raft Paper的Figure2填的property
type Raft struct {
mu sync.Mutex // Lock to protect shared access to this peer's state
peers []*labrpc.ClientEnd // RPC end points of all peers
persister *Persister // Object to hold this peer's persisted state
me int // this peer's index into peers[]
dead int32 // set by Kill()
//Persistent state on all servers
currentTerm int
votedFor int
log []int
//additional property
currentState ServerState
lastReceived time.Time
//Volatile state on all servers
commitIndex int
lastApplied int
//Volatile state on leaders
nextIndex []int
matchIndex []int
}
AppendEntriesArgs跟AppendEntriesReply对着RequestVoteArgs照葫芦画瓢就行了
//AppendEntries
type AppendEntriesArgs struct {
Term int
LeaderId int
PrevLogIndex int
PrevLogTerm int
Entries []int
LeaderCommit int
}
type AppendEntriesReply struct {
Term int
Success bool
}
Make 重点在于go rf.LeaderElection() 以及go rf.StateMonitor()
func Make(peers []*labrpc.ClientEnd, me int,
persister *Persister, applyCh chan ApplyMsg) *Raft {
rf := &Raft{
}
rf.peers = peers
rf.persister = persister
rf.me = me
// Your initialization code here (2A, 2B, 2C).
rf.currentTerm = 1
rf.votedFor = -1
rf.log = []int{
}
rf.commitIndex = 0
rf.lastApplied = 0
//addition property
rf.currentState