如何基于Raft绕过​分布式算法一致性的那些痛?

 

 

3、以上关于接受Ready()消息的处理代码中,除了之前提到的两点外,剩下的就是关于WAL(Write Ahead Logging 预写式日志多用于实现数据库原子性事务)和snapshot的相关处理了。

 

通过代码看到Ready()里收到的每一条消息都会先调用wal。Save,由wal。Save将相关的信息保存到WAL中,当操作积累到一定的数量时,则会通过saveSnapshot将目前的全量数据(包括状态和已经接受到的所有数据)保存到snapshot中, 然后调用wal。ReleaseLockTo释放掉已经存入snapshot中的操作。

 

这点与许多数据库实现的WAL原理( WAL机制的原理,是修改并不写入到数据库文件中,而是写入到另外一个称为WAL的文件中;如果事务失败,WAL中的记录会被忽略,撤销修改;如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改)是一样的。

 

注:最后别忘了调用RaftNode。Advance()。

 

  • 关于日志压缩

 

之前提到WAL会将RaftNode的每次操作记录下来,而且在RaftCluster中leader不删除日志,仅追加日志,因此随着系统的持续运行,WAL中内容越来越多,导致日志重放时间增长,系统可用性下降。快照(Snapshot)是用于“日志压缩”最常见的手段,Raft也不例外。

 

具体做法如下所示(图片来自网络):

 

 

与Raft其它操作Leader-Based不同,snapshot是由各个节点独立生成的。除了日志压缩的功能,snapshot还可以用于同步状态。

 

四、总结

 

以上仅仅只是跑起来一个简单的RaftCluster,关于服务怎么和嵌入的RaftCluster结合,以及leader切换,节点的增删等等还是有不少的问题等着我们一起去探讨和解决。有关Raft的更多资料可以参考:

 

  • Raft动画演示 

    http://thesecretlivesofdata.com/raft/ 

  • Raft论文

    https://ramcloud.stanford.edu/wiki/download/attachments/11370504/raft.pdf