6.5840 Lab3A Raft Leader Election - 前情提要
log
- Log是Leader用来对操作排序的一种手段。
- 在一个(非Leader,也就是Follower)副本收到了操作,但是还没有执行操作时。该副本需要将这个操作存放在某处,直到收到了Leader发送的新的commit号才执行
- Leader需要在它的Log中记录操作,因为这些操作可能需要重传给Follower。如果一些Follower由于网络原因或者其他原因短时间离线了或者丢了一些消息,Leader需要能够向Follower重传丢失的Log消息。所以,Leader也需要一个地方来存放客户端请求的拷贝。即使对那些已经commit的请求,为了能够向丢失了相应操作的副本重传,也需要存储在Leader的Log中。
- 所有节点都需要保存Log还有一个原因,就是它可以帮助重启的服务器恢复状态。
AppendEntries
- Leader 需要同步日志到 follower
- Leader 需要维护 commit ,超过半数节点复制日志后commit
RequestVote
- 不能投票给比自己日志晚的节点
args.LastLogTerm < rf.logs[lastLogIndex].Term ||(args.LastLogTerm == rf.logs[lastLogIndex].Term && args.LastLogIndex < lastLogIndex)
persistence
需要持久化的参数
- term : 用于防止节点重启后使用过期的任期,避免出现多个 Leader 或无效选举。
- logs : 存储所有已接收但未提交/已提交的操作记录,是状态机一致性的基础。
- vote_for : 确保同一任期内只能投一票,防止重复投票导致选举冲突。
为什么commitIndex和lastApplied不用?
follower
经过正确的AppendEntries RPC
后 日志和Leader
相同,此时commitIndex=min(leaderCommit, follower max index)
Leader
重启后,通过比较其他节点的日志(matchIndex
)重新计算commitIndex
lastApplied
,状态机可以通过重放日志来实现同步。如果状态机是快照,那么在快照中会记录lastIncludedIndex
和lastIncludedTerm
需要持久化的时机
当需要持久化的参数改变时,需要持久化
- currentTerm 变更:节点发现更高任期(如收到 RPC 请求或选举超时)。
- votedFor 变更:为某个 Candidate 投票后(响应 RequestVote)。
- log[] 变更:追加新日志(Leader 接收客户端请求)或覆盖不一致日志(Follower 同步日志)。