MIT-6.824
MIT-6.824 copied to clipboard
Lec 6:Raft实现
课前阅读论文:Raft Extended(2014)第六节到后面 讲义:英文 FAQ:英文
本期问题(请大家在本issue中直接回答):Figure13中第8步能否导致状态机重置,即接收InstallSnapshot RPC消息能否导致状态回退
etcd中的实现(InfluxDB也在使用):
这个库实现了raft协议核心的内容,比如append log的逻辑,选主逻辑,snapshot,成员变更等逻辑。没有实现消息的网络传输和接收,库只会把一些待发送的消息保存在内存中。
Raft的Go实现(没有再维护了):
另一个Go实现(BoltDB使用):
涉及Raft日志(Lab2B)与持久化(Lab2C)的实现细节
Raft日志(Lab2B)
提交流程:client RPC -> Start() -> 多数提交协议 -> applyCh(所有节点成功提交后都要发送?) 实际实践中还需要保证在切换leader时 client的处理: 停止读取,重复发送等,甚至包括特殊处理丢失的操作、乱序递交等。
leader发送的AppendEntities请求中包含prevLogIndex和prevLogTerm信息,用于帮助follower判断能否采用,如果从follower返回false则leader回退nextIndex[follower]信息,保证下次发送可以接受 follower需要根据leader的prevLogTerm删除自身不相符的部分并同步prevLogIndex之后的日志 可以谨记的是新leader不会回退任何已经committed记录
上节课的问题答案:
上述的每次回退一个要求发起一次rpc,非常慢! 下面是一个改进版 if follower rejects, includes this in reply: the follower's term in the conflicting entry the index of follower's first entry with that term if leader knows about the conflicting term: move nextIndex[i] back to leader's last entry for the conflicting term else: move nextIndex[i] back to follower's first index
持久化(Lab2C)
Log压缩及快照(Lab3B)
节点变更(未包含在Lab内)
性能
- 除心跳及选举线程外还需要启动一个长期线程来处理已经提交的日志log向applyChan顺序提交的逻辑,其他线程递增commitIndex时可以唤醒这个提交线程来保证最终顺序与预想的一致。
- RPC发送及接收处理最好放在go协程里面,还需要考虑到实际并发RPC里面可能出现网络导致RPC到达顺序与预想的不一致
Raft锁设计建议:英文
请问
if follower rejects, includes this in reply: the follower's term in the conflicting entry the index of follower's first entry with that term if leader knows about the conflicting term: move nextIndex[i] back to leader's last entry for the conflicting term else: move nextIndex[i] back to follower's first index
的英文讲义原文是在哪里呢?我在做这个优化,想参考一下,thx
请问
if follower rejects, includes this in reply: the follower's term in the conflicting entry the index of follower's first entry with that term if leader knows about the conflicting term: move nextIndex[i] back to leader's last entry for the conflicting term else: move nextIndex[i] back to follower's first index
的英文讲义原文是在哪里呢?我在做这个优化,想参考一下,thx
https://pdos.csail.mit.edu/6.824/notes/l-raft2.txt
在解决图8的问题是,论文中提到了这么一个解决方案:
Raft handles this by having each leader commit a blank no-op entry into the log at the start of its term. 在新选举出一个leader后,该leader会立即发送一个该term的“空Log”。当该空log被大多数服务器复制提交后,可认为该log之前的log已经全部被提交。
我想问下,关于“发送一个空操作的Log”的问题。 我在实现了基本的AppendEntries逻辑后,在这基础上添加“发送一个空操作的Log”的操作时,发现代码变得比较复杂。比如对nextIndex,matchIndex,以及commitIndex的维护上。此外,实验的测试代码也不允许将空Log添加到log数组中。 我想问下关于这一块怎么实现会比较好,或者有哪些可以参考的代码? 非常感谢=。= 描述的不清晰==如果您觉得有必要更清晰的描述的话,我会好好的整理一下再发出来
在解决图8的问题是,论文中提到了这么一个解决方案:
Raft handles this by having each leader commit a blank no-op entry into the log at the start of its term. 在新选举出一个leader后,该leader会立即发送一个该term的“空Log”。当该空log被大多数服务器复制提交后,可认为该log之前的log已经全部被提交。
我想问下,关于“发送一个空操作的Log”的问题。 我在实现了基本的AppendEntries逻辑后,在这基础上添加“发送一个空操作的Log”的操作时,发现代码变得比较复杂。比如对nextIndex,matchIndex,以及commitIndex的维护上。此外,实验的测试代码也不允许将空Log添加到log数组中。 我想问下关于这一块怎么实现会比较好,或者有哪些可以参考的代码? 非常感谢=。= 描述的不清晰==如果您觉得有必要更清晰的描述的话,我会好好的整理一下再发出来
@M1178475702 可以仅在 kvServer.Get 的时候做, 而不是在选举成为 leader 的时候做.
The no-op text at the end of Section 8 is talking about an optimization in which the leader executes and answers read-only commands (e.g. get("k1")) without committing those commands in the log.