每个实验任务都标有难度,以大致表示我们预期该任务需要多长时间:
简单:几个小时。
中等:约 6 小时(每周)。
困难:超过 6 小时(每周)。如果你开始得太晚,你的解答不太可能通过所有测试。
大多数实验只需要适量的代码(每个实验部分可能只需几百行),但在概念上可能很困难,可能需要大量的思考和调试。有些测试很难通过。
不要在实验截止前一晚才开始做;分多次、分散在多天完成实验效率更高。在分布式系统中追踪错误是很困难的,因为涉及并发、崩溃和不可靠的网络。
高效的调试需要经验。系统化会有所帮助:形成一个关于可能原因的假设;收集可能相关的证据;思考你收集到的信息;根据需要重复。对于长时间的调试,做笔记会有帮助,既可以积累证据,也可以提醒自己为什么排除了某些先前的假设。
最有效的调试技术通常是向你的代码添加打印语句,运行失败的测试并将打印输出收集到文件中,然后查看输出文件以确定问题开始出错的地方。你可能需要迭代,随着对问题了解的深入添加更多打印语句。
不同节点之间以及单个节点内线程之间的并发可能导致操作以意想不到的方式交错。例如,Raft 节点完全可能在上一任领导者仍然认为自己是领导者的情况下被选为领导者,或者领导者发送了 RPC 但在失去领导权后才收到回复。添加打印语句可以帮助你发现这些情况。
请随意查看测试代码(mr/mt_test.go、raft1/raft_test.go 等)以了解测试的内容。你可以向测试添加打印语句以帮助理解它们在做什么以及为什么失败,但请确保在提交前用原始测试代码能通过了。
Raft 论文的图 2 必须相当严格地遵循。很容易遗漏图 2 中要求检查的条件,或者要求执行的状态变更。如果你有 bug,重新检查你的所有代码是否紧密遵循图 2。
在编写代码时(即在你有 bug 之前),值得为代码假设成立的条件添加显式检查,也许可以使用 Go 的 panic。这样的检查可以帮助检测后续代码无意中违反假设的情况。
助教很乐意在答疑时间帮助你思考代码,但如果你已经尽可能深入地研究了情况,你有限的答疑时间可能会获得最大的收益。