Mit6.824-lab2c-2022

Mit6.824-lab2c-2022

写在前面

如果你的2a和2b完成度很高的话,2c是整个实验最简单的部分,只要完成持久化的两个方法再在所有需要持久化的部分进行调用即可。反之2c的debug就是一场噩梦,甚至有可能要重构前面的代码以通过所有2c的测试

实验内容

  1. 持久化

这部分其实很简单,按照示例完成persist和readPersist,并且在所有需要持久化的地方调用就可以了

  1. 日志增量回退

这部分笔者在2b部分就完成了,简单来说就是直接退回到Follower上一次Apply的地方。虽然简单粗暴,但通过lab2所有的测试已经足够了。当然有能力的同学可以试着自己完成官方推荐的方法,按照Term退回,或者像老师说的做一个二分的快速退回。

实现代码

  1. 持久化方法
func (rf *Raft) raftState() []byte {
	w := new(bytes.Buffer)
	e := labgob.NewEncoder(w)
	if e.Encode(rf.currentTerm) != nil ||
			e.Encode(rf.votedFor) != nil ||
			e.Encode(rf.log) != nil {
			return nil
	}
	return w.Bytes()
}


func (rf *Raft) persist() {
	// Your code here (2C).
	// Example:
	if data := rf.raftState();data == nil{
		log.Printf("peer :%d has some thing wrong in persist",rf.me)
	}else{
		rf.persister.SaveRaftState(data)
	}
}

在所有currentTerm,votedFor和log有改变的地方调用即可

  1. 读取持久化
func (rf *Raft) readPersist(data []byte) {
	if data == nil || len(data) < 1 { // bootstrap without any state?
		return
	}
	r := bytes.NewBuffer(data)
	d := labgob.NewDecoder(r)
	var currentTerm, votedFor int
	var logs []Entry
	if d.Decode(&currentTerm) != nil ||
		d.Decode(&votedFor) != nil ||
		d.Decode(&logs) != nil {
		log.Printf("peer :%d has some thing wrong in read  persist",rf.me)
		return
	}
	rf.currentTerm = currentTerm
	rf.votedFor = votedFor
	rf.log = logs
}

make方法对Raft初始化之后调用即可

其他建议

1.参数选择

推荐选举超时时间在800ms-1200ms,心跳发送间隔为50ms

2.选举失败

选举失败后如果没有变成Follower应该做什么,按照paper上示意图应该是进行下一次选举,那是否应当等待,以及等待多久。这个根据实现的不同应该有不同的考虑:

  1. 如果选举通过goroutine实现,不考虑其超时的情况,那么应当在发起选举后就立刻置选举超时时间为0,并在超时后重新发起选举。
  2. 选举通过for循环完成,也就是选举后等待该选举完成或超时后,再重新发起新一轮选举,此时也应保证在选举发起后等待一个选举超时时间后重新发起选举。

注意:一定要保证等待时间的随机性,不然会导致多轮同时竞选,同时保证选举超时时间足够长,不然会导致某个无法被选举的Follower(如log过短)连续多次发起选举,不断刷新其他peer的选举等待

测试内容

TestPersist12CTestPersist22CTestPersist32C:基础测试,断联peer后重连查看是否正常持久化数据
TestFigure82C:针对Figure.8的情况进行测试,每个操作都要求领导者(如果有)追加log。如果有一个领导者,那么该领导者很快就会失败,概率很高(可能不执行命令),或者过一段时间后崩溃,概率很低(很可能执行命令)。如果活动服务器的数量不足以构成大多数服务器,也许可以启动一个新服务器。新任期内的领导者可能会尝试复制尚未提交的日志条目。
TestUnreliableAgree2C:测试不稳定网络情况下能否达成一致,也就是RPC可能会有1-2秒的延迟或丢失
TestFigure8Unreliable2C:网络不稳定情况下测试Figure.8的情况
TestReliableChurn2CTestUnreliableChurn2C:分别在稳定和不稳定情况下,每个peer有低概率崩溃重启,在此基础上,进行大量的log追加与提交。

调试建议

1.参数选择

这个实验最容易出现的错误在TestFigure8Unreliable2C,而且不是因为Figure8的情况而是因为不稳定网络的情况,在这个测试下,需要在RPC高延迟的情况下10秒内选出leader并完成提交,同时存在小分区内的leader(该leader已经接收了超长的log),保证分区结束后这个leader不能选举成功。这就要求选举有以下几个条件:

  1. 选举超时时间足够长,避免小分区leader反复选举,一直刷新Term
  2. 选举超时时间足够随机,避免多个peer同时选举同时失败
  3. 单位时间发起选举次数足够多,以保证10秒内发起足够多次数的选举使得在RPC高延迟,丢包下仍有可能选举成功
2.及时发送心跳更新

尽量及时,多次通过心跳发送更新信息(log追加,commitIndex更新)。

3.进行足够的测试

如果几十次测试就有一次错误,肯定某处逻辑存在问题,如果几百次测试有一次错误,可能某处corner case没有考虑到。2c的测试时间很长,必须用脚本进行足够多的测试找出所有的错误。必要时可以在config.go中添加log,以打印出自己需要的错误信息。一个逻辑自洽的代码至少应该千次运行无错,留下错误到2d中进行debug只会更痛苦。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值