Lab2 A&&B
写完2A,再写2B,就会发现2A2B是一体的,2B逼着你去重改2A的框架。
主结构
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 所有peers的RPC端点
persister *Persister // Object to hold this peer's persisted state 保存这个peer的持久化状态的对象
me int // this peer's index into peers[] 在peers数组里的下标(索引index)
dead int32 // set by Kill()
// Your data here (2A, 2B, 2C).
// Look at the paper's Figure 2 for a description of what
// state a Raft server must maintain.
// vote
currentTerm int
votedFor int
//lastResetElectionTime time.Time
electionTimeOut time.Time
// entries
log []Entry
commitIndex int
lastApplied int
// for leader
nextIndex []int
matchIndex []int
// common
applyCh chan ApplyMsg
stage int
}
type Entry struct {
Term int
Command interface{}
}然后就是要先完成Leader选举,先补充完Make:
lab的提示里面建议用 sync.Cond 来实现 apply ticker的功能,即让apply ticker 在 rf.lastApplied >= rf.commitIndex时休眠,但是我想着要唤醒这个goroutine是比较麻烦的,要在多数状态机应用之后再通过心跳广播给各个follower,这样感觉费力不讨好。所以我直接用了time.sleep()。不过是以小于心跳的时间间隔来检查ticker,因为没了广播的话,那些重连的机子可能需要非常频繁的去应用日志。
leader 选举
再 candidateElectionTicker中,每100ms检查一次选举超时,如果选举超时,就更改为candidate并重置超时时间,然后发起选举
然后就是去获取选票的函数实现,过程写在注释中:
选票的最后环节就是图二中的两条选举规则,遵循rule 1 2 写就行了
AppendEntries
选举成功之后,要想pass 2A还需要一个AppendEntries来发送心跳,这个比较简单,不用啥规则,leader直接发送就行。
然后2B的内容,就需要先完善Start()里面的逻辑:
start()是Leader一次获取一条命令添加到自己的日志,所以实现起来比较简单。我使用心跳来发送log
在心跳检查的ticker中,每隔50ms进行一次心跳/日志发送
AppendEntries rpc的内容:
日志应用 appliedTicker
实现完日志添加后,就需要应用到状态机:
至此就可以pass 2A和2B的所有test了
Last updated