raft:日志清理和AppendEntries

raft: log cleaning and AppendEntries

日志清理会删除对当前状态没有贡献的条目,那么如果慢速关注者或新成员需要它们,如何为这些删除的条目构造AppendEntries?需要修改 AppendEntries 以便它可以包含非连续条目?或者改用快照?

Copycat implements a form of incremental compaction using an algorithm that's somewhat similar to the log cleaning algorithm described in the Raft dissertation。因此,有一些先例和代码可以说明如何执行此操作。 Copycat 的增量压缩算法与 Raft 文献中描述的算法不同,它在压缩后保留日志中条目的位置以利用顺序读取而不是将条目复制到日志的头部,但是 AppendEntries RPC发送给关注者仍然可以在条目批次中有间隙地发送。

我们通过在 AppendRequest 批次中包含每个条目的索引来简单地处理丢失的条目。但这也需要日志中的某种机制来跳过关注者的条目。如果跟随者正在从领导者日志的压缩段中接收条目,则跟随者必须通过在将条目写入日志时跳过条目来复制领导者日志的结构。

在 Raft 文献中没有广泛描述的 Raft 增量压缩还有一些其他挑战,特别是在处理墓碑方面。逻辑删除的问题之一是,在将它们应用到所有服务器之前,它们无法从日志中删除。如果逻辑删除在复制到跟随者(可能已分区)之前已提交并从领导者的日志中删除,则该跟随者可能永远不会删除其状态。在 Copycat 中,这需要添加一个 globalIndex 来跟踪存储在所有服务器上的最高索引。

但我离题了,我意识到我过度回答了你的问题。 Raft 中的增量压缩是一个有趣且具有挑战性的问题。如果你有兴趣阅读更多关于它是如何在 Copycat 中解决的,我已经写了 extensive documentation on the Copycat's incremental compaction algorithm,包括对处理墓碑的各种问题的深入描述以及在增量压缩算法之上实现快照的方法.

如果你从 Copycat 的文档中学到一件事,那很可能是 Raft 中增量压缩的复杂性很大。我们花了好几个月的时间才算出其中的所有算法,但也许我们学到的教训对你有用。

可以肯定的是,在 Raft 中实现快照比 Copycat 中的增量压缩算法要容易得多。但它仍然存在一些复杂性。例如,Java 不太适合 fork 进程以防止在快照期间阻塞,这也是我们选择为 Raft 编写增量压缩算法的原因之一。在 Copycat 中实现对大型快照的支持需要将完整的状态机状态复制到内存中或添加领导者传输机制以确保领导者在对大型状态机进行快照时不会被阻塞。根据您环境的实际情况权衡选项。