I’m learning MIT 6.824: Distributed Systems recently. This post is my solution to lab 2. This lab requires to implement a Raft system.
Part 2A: leader election
-
Election ticker and heartbeat ticker
For simplity, each Raft server starts two goroutines, responsing for timeout elections and heartbeats respectively. The Raft server controls its behavior via channels.
For example, the election ticker has 3 channels:
reset,pauseandcontinue. It loops to select a random timeout,resetsignal orpausesignal. For (1)timeout, it converts to candidate (which starts a election); for (2)reset, it restarts a loop; for (3)pause, it blocks to wait for another signal fromcontinue.
The heartbeat ticker is almost the same, except it has no
resetchannel. -
convertToA difficulty of this part is how to handle states switching. I define a helper function
func (rf *Raft) convertTo(s State).To enum all possible
(oldState, newState)pairs, I use a trick here:Statetype is defined asintand each state has a unique bit.type State int const ( Follower State = 1 << iota /* 0x1 */ Candidate /* 0x2 */ Leader /* 0x4 */ __nState = iota /* 3 */ )So that each pair has a unique integer and thus can be used in
switch-case.func (s State) to(t State) int { return int(s | t<<__nState) } switch oldState.to(newState) { case Follower.to(Candidate): /* ... */ case Candidate.to(Candidate): /* ... */ /* ... */ }In Figure 4 of the paper, 5 edges are defined. For convinience, I add
Follower->Followerto deal with election timer reset.
-
Election,
RequestVoteRPCTo do an election,
sendRequestVoteto peers and wait for reply. In case some connections are too slow to reply in a timeout, election goroutine should not wait for all peers replying. Instead, when a peer reply,atomic.Addthe number of votes, if it just reaches the majority, call theconvertTo(Follower). -
Heartbeat, i.e. empty
AppendEntriesRPC