kikimo

Raft 笔记(三)——快照

Raft 的 log 保存在内存中, 内存无法支撑 log 无限增长, 因此 Raft 用快照技术将某个时间段前的状态转成快照并存储在次盘上, 这个时间段之前的的 log 就可以删掉了。 Raft 快照存储的是从 log 开始到具体某个时间点下的已经提交的日志的状态机执行结果,而不是具体的 log 内容。 除此以外 Raft 快照中还包含两个字断 lastIncludedIndex 和 lastIncludedTerm, 这两个字段在 AppendEntries RPC 调用时用来执行一致性检查, 例如当我们网快照之后的 log append 日志时可能就需要检查快照中最后一条日志的 inddex 和 term 是否匹配。 Raft 中的每个节点都会执行快照转存操作, 因为快照转存针对的都是已经提交的日志, 所以我们不用担心数据不一致的问题(Raft 算法已经保证了节点间已提交日志的一致性)。 节点在什么时候执行快照转存操作? Raft 论文中没有限定具体的执行时机, 但给出一个简单的策略:当内存中 log 日志的大小达到某个固定值的时候便执行快照转存。

Raft 为快照处理添加了一个新的 InstallSnapshot RPC. 通常节点自己做快照转存就可以了, 但在某些特殊情况下, 节点的日志可能大幅落后于主节点, 比如这是一个新增的节点, 或者由于网络延迟导致节点数据落后较多, 这时候主节点就会向这些节点调用 InstallSnapshot RPC。 Leader 如何判断 Follower 的日志落后太多, 也就是它如何具体判断 InstallSnapshot RPC 的调用时机? 当 Leader 已经将部分 Log 丢弃(也就是这部分内容已经转存成快照了)时, 如果它发现 Follower 上还没同步这部分数据, 它就会发起 InstallSnapshot RPC。 InstallSnapshot 可能会把快照分多次发送, 所以 RPC 接口参数里有个done字段表示快照是否已经传输完毕, 除此以外还有一个offset字段表示当前数据的偏移量——InstallSnapshot传输的都是二进制数据。 在实现 InstallSnapshot 的时候一个需要特别留意的地方就是, RPC 可能是乱序抵达的,代码上的实现需要考虑这个问题。 Follower 在收到全部的快照数据后用新的快照替代当前的快照, 并且丢弃日志中已经包含在快照中的数据。