MIT6.824(6.5840)Lab2-Raft
lab2做完一直没写博客总结,现在来补上,算是对raft的一个回顾和思考吧。
写完lab2最大的感受就是:如果你是一个新手小白,第一次接触raft,对于raft不是很熟悉,而且raft的长篇论文看的懵懵懂懂,那么我十分建议你花时间完成lab2,边看论文边完成实验。这个实验基本是按照论文的描述进行实现的,在实验的过程中能很好地掌握和理解raft的各种细节,加深对于raft的理解。
lab2分为ABCD四个实验,分别实现选主、日志复制、持久化和日志压缩四大部分。接下来分别总结一下四个实验。
lab2A 选主
这部分主要是实现raft中的leader选举机制以及心跳机制,整体相对是较为简单的实验。
结构体
结构体主要是按照raft论文中的结构体进行实现,具体如下图:
首先是raft的主结构体:
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()
applyChan chan ApplyMsg //每个节点用于提交应用日志的通道
state State //节点当前的状态,分为leader,candidate和followe三种
currentTerm int //节点当前所处的任期
votedFor int //节点当前任期内所投的选举票,即选举谁作为leader
logs []LogEntry //存储日志
commitIndex int //节点已经提交的日志的最大下标,记录当前日志提交到哪,初始化为0
lastApplied int //节点已经应用的最新日志下标,记录当前状态机应用到哪了
nextIndex []int //记录将要发送给每个节点的日志的起始下标
matchIndex []int //当前节点于其他节点已经同步复制的日志的最大下标
electionTimer *time.Timer //选举定时器,定时触发选举操作
heartbeatTimer *time.Timer //心跳定时,定时触发心跳机制,及时发现故障
}
type LogEntry struct {
Term int //日志任期
Command interface{
} //日志的具体命令
}
然后是AppendEntries RPC的相关结构体
type AppendEntriesArgs struct {
Term int
LeaderId int
PrevLogIndex int //追加的新日志的前面一个日志的下标,为nextIndex[peer] - 1
PrevLogTerm int //追加的新日志的前一个日志的任期
Entries []LogEntry
LeaderCommit int
}
type AppendEntriesReply struct {
Term int
Success bool
}
最后是RequestVote RPC的相关结构体
type RequestVoteArgs struct {
Term int
CandidateId int
LastLogIndex int //申请者最后一条日志的下标
LastLogTerm int //申请者最后一条日志的任期
}
// example RequestVote RPC reply structure.
// field names must start with capital letters!
type RequestVoteReply struct {
Term int
VoteGranted bool
}
主要流程
- 初