MIT-6.824 分布式系统 课后实验 Lab2 A/B/C (Raft Election, Log Replication, Persistence)

MIT-6.824 分布式系统 课后实验 Lab2 A/B/C (Raft Election, Log Replication, Persistence)

💡 原文中文,约14300字,阅读约需35分钟。
📝

内容提要

本文介绍Raft分布式一致性算法的Go实现。Raft包含leader、candidate、follower三种角色,通过随机选举超时避免选票分裂,leader定期发送心跳维持权威。日志由任期、序号和命令组成,需过半节点复制后才提交。实现中将角色切换与定时器绑定,任期与投票对象封装为Term结构,核心循环按角色发送心跳或投票请求并处理事件。持久化仅需currentTerm、VoteFor和logs。作者总结常见错误包括未重置选举超时、日志校验不全、任期更新不及时,并指出该实现未支持集群成员变更。

🔎

延伸解读

角色切换与定时器绑定的设计考量

作者将Raft角色变更与ticker重置绑定在change方法中,确保状态转换时定时器行为同步更新。例如candidate转为leader时启动心跳ticker并重置nextIndex和matchIndex,转为follower时停止心跳并重置随机选举超时。这种设计减少了因定时器未及时调整导致的选举频繁或心跳缺失问题,是实现中值得注意的工程细节。

日志一致性校验的关键点

处理AppendEntries时,follower需先检查PrevLogIndex和PrevLogTerm是否匹配,再逐条比对日志任期,遇到冲突则删除后续日志并覆盖。作者曾因未完整校验leader日志是否更新就返回成功,导致集群日志不一致。这说明日志复制不仅要看序号,还要严格比较任期,否则可能破坏Raft的安全性。

持久化的范围与时机

文章指出只需持久化currentTerm、VoteFor和logs,这与Raft论文一致。follower应在响应请求前完成持久化,leader在commitIndex增加后持久化。作者在lab2C中因持久化与网络分区结合而遇到困难,提示读者需注意崩溃恢复后状态的一致性,避免因持久化时机不当导致重复投票或日志丢失。

实现局限与调试建议

该实现假定集群成员数量固定,未包含成员变更,真实场景中配置可能动态调整,这是明显的局限。作者建议将响应leader的错误信息放入Debug字段,便于只关注leader日志排查问题。分布式系统问题难复现,这种针对性的日志设计能提升调试效率,但读者也需意识到该demo未覆盖生产级需求。

❓

Q&A

Raft算法中节点有哪几种角色,各自负责什么?

Raft有leader、candidate、follower三种角色。leader负责处理客户端请求并向其他节点发起日志复制;candidate在集群没有leader时发起投票;follower接收leader的命令。

Raft选举超时时间为什么要设计成随机的?

随机选举超时是为了防止同一时刻多个节点同时成为candidate导致选票分裂,从而避免选举无法产生leader。

Raft日志需要包含哪些信息,日志在什么条件下才能提交?

日志必须包含term(任期)、index(序号)和command(具体内容)。只有leader确认集群中过半节点完成了日志复制,该日志才能提交。

实现Raft时,哪些状态需要持久化?

根据论文,只有currentTerm、VoteFor和logs需要持久化。follower要在响应请求之前完成持久化,leader在commitIndex增加之后完成持久化。

在Lab2B日志复制实现中,作者遇到过哪些常见错误?

常见错误包括:收到合法AppendEntries后未重置选举超时导致频繁选举;未完整校验Leader日志是否更新就回复成功导致日志不一致;收到AE或RV请求后未及时更新Term或未判断对方Term有效性。

这个Raft实现支持集群成员变更吗?

不支持。该实现假定集群成员数量固定不变,没有包含集群成员变更功能,而真实场景下集群成员配置可能改变。

🏷️

标签

➡️

继续阅读