这个实验我做了将近20个工作日,耗时真挺久
温馨提示
1.写一个getlast函数,专门用来查最后一条log,一个get函数,输入index,返回log
2.做好备份,你的很多修改带来的变化是很大的.这里我用的vscode远程开发,有个时间线的功能,我觉得非常好用,墙裂推荐.
3.Debug
const Debug = false
func DPrintf(format string, a ...interface{
}) (n int, err error) {
if Debug {
file := "./" + "log_kv" + ".txt"
logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
if err != nil {
panic(err)
}
log.SetOutput(logFile) // 将文件设置为log输出的文件
log.Printf(format, a...)
}
return
}
Lab2A:leader选举
1.通读raft论文 重点阅读firgure2
2.Start early,千万不要一直沉浸在论文,快点开始,很多东西都会豁然开朗,如果你不动,光用脑子想,会很累
由于步骤太多,我只讲一些重要函数中(很抱歉,我不能提供的代码,过段时间我在开放)
1. func (rf *Raft) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply)
- 判断args.Term,如果更小则拒绝
- 更新CurrentTerm,如果args.Term更大就更新(这里注意一定要把peer调成candidate,为什么我后面会讲)
- restrict election 得到最后一个日志的Term 和 Index
- 如果args.LastLogTerm更小 说明不够新 拒绝
- 如果Term一样 Index更小 说明不够新 拒绝
- 判断是否重复投票 如果已经投票,并且投给的不是args.CanidateId && args.Term==CurrentTerm,拒绝
- 上面的情况都没有出现,可以投票
2.func (rf *Raft) ticker()
每当启动一个peer,都要 go ticker(),我的ticker与election都写的很乱,很多地方没有梳理
for !rf.killed() {
if peer是follower && 超时未收到心跳 {
转为 candidate
随机休眠一段时间
如果休眠结束 状态不是 candidata {
go ticker()
return
}
开始选举
return
}
if peer是leader && Term时间耗尽{
转为 candidate
随机休眠一段时间
如果休眠结束 状态不是 candidata {
go ticker()
return
}
开始选举
return
}
if peer是leader {
发送心跳
}
休眠一段时间
}
Lab2B
1.raft论文细看
2.多打印日志,我基本上在每个函数的第一行都会打印输入的参数
func (rf *Raft) AppendEntries(args *AppendEntriesArgs, reply *AppendEntriesReply)
这个函数是我写的最长的函数了,在我第一次完成lab2B,之后任然在修改,缝缝补补.
由于没有重构,还留存一些没用的部分,所以看起来会很乱
func (rf *Raft) AppendEntries(args *AppendEntriesArgs, reply *AppendEntriesReply) {
rf.mu.Lock()
defer rf.mu.Unlock()
defer DPrintf("raft.me=%d args %v reply %v", rf.me, args, reply)
DPrintf("raft.me=%d rf.LastSsIndex %d rf.CurrentTerm %d get %d rpc AppendEntries but no judge args %v log %v",
rf.me, rf.LastSsIndex, rf.CurrentTerm, args.Me, args, rf.Log)
rf.now = time.Now()
reply.Term = rf.CurrentTerm
if args.CurrentTerm == rf.CurrentTerm && rf.Raftstate == 1 {
DPrintf("raft.me=%d refuse follower's append RPC", rf.me)
return
}
//if args.CurrentTerm 更小 拒绝
if args.CurrentTerm < rf.CurrentTerm {
DPrintf("raft.me=%d refuse %d append because of term args.CurrentTerm %d < rf.CurrentTerm %d",
rf.me, args.Me, args.CurrentTerm, rf.CurrentTerm)
reply.Append = false
return
}
// if args.CurrentTerm 更大 更新Term,将状态设置成follower
if args.CurrentTerm > rf.CurrentTerm {
DPrintf("r