在 《TiKV 源码解析系列文章(二)raft-rs proposal 示例情景分析》 中,我们主要介绍了 raft-rs 的基本 API 使用,其中,与应用程序进行交互的主要 API 是:
-
RawNode::propose 发起一次新的提交,尝试在 Raft 日志中追加一个新项;
-
RawNode::ready_since 从 Raft 节点中获取最近的更新,包括新近追加的日志、新近确认的日志,以及需要给其他节点发送的消息等;
-
在将一个 Ready 中的所有更新处理完毕之后,使用 RawNode::advance 在这个 Raft 节点中将这个 Ready 标记为完成状态。
熟悉了以上 3 个 API,用户就可以写出基本的基于 Raft 的分布式应用的框架了,而 Raft 协议中将写入同步到多个副本中的任务,则由 raft-rs 库本身的内部实现来完成,无须应用程序进行额外干预。本文将对数据冗余复制的过程进行详细展开,特别是关于 snapshot 及流量控制的机制,帮助读者更深刻地理解 Raft 的原理。
一般 MsgAppend 及 MsgAppendResponse 的处理
在 Raft leader 上,应用程序通过 RawNode::propose 发起的写入会被处理成一条 MsgPropose 类型的消息,然后调用 Raft::append_entry 和 Raft::bcast_append 将消息中的数据追加到 Raft 日志中并广播到其他副本上。整体流程如伪代码所示:
fn Raft::step_leader(&mut self, mut m: Message) -> Result<()> {
if m.get_msg_type() == MessageType::MsgPropose {
// Propose with an empty entry list is not allowed.
assert!(!m.get_entries().is_empty());
self.append_entry(&mut m.mut_entries());
self.bcast_append();
}
}
这段代码中 append_entry的参数是一个可变引用,这是因为在 append_entry函数中会为每一个 Entry 赋予正确的 term 和 index。term 由选举产生,在一个 Raft 系统中,每选举出一个新的 Leader,便会产生一个更高的 term。而 index 则是 Entry 在 Raft 日志中的下标。Entry 需要带上 term 和 index 的原因是,在其他副本上的 Raft 日志是可能跟

本文详细介绍了Raft分布式一致性协议中数据冗余复制的过程,包括Propose和ReadyAPI的使用,MsgAppend及MsgAppendResponse的消息处理,以及Leader如何维护副本的Progress状态进行流量控制。特别讨论了Snapshot的生成和应用,以及Pipeline优化对性能的影响。
最低0.47元/天 解锁文章
156

被折叠的 条评论
为什么被折叠?



