1、前言
此工程实现来自 github 链接:https://github.com/stateIs0/lu-raft-kv。题者说是一个基于 raft 的分布式 kv 系统,但实际上就是一个完整的 raft 实现(虽然论文说的重发他没去做了,但不影响整体思路),可以把它当成 raft 论文的实现,具体论文可以参照 raft 论文或者其翻译版。
2、思路
RPC 框架采用 sofa(任何 RPC 都可),本地存储采用 RocketsDB,是一款比较好用的嵌入式数据库(或者自己文件实现也可,只是这边重点在于 Raft,不过一般开源的中间件如 zk 都会实现自己的内存数据库)。Raft 提交分为两阶段 prepare 和 commit 阶段,所以代码中 db 初始化了两个:logDb、machineDb,分别存在日志模块、状态机模块,对应两阶段的存储。整个代码的类图如图所示:
整个系统由 RaftClient 与 DefaultRpcServer 进行交互,DefaultRpcServer 只暴露了一个 handlerRequest 接口与 client 或者其他 node 交互。
每个 DefaultNode 都由 Consensus(一致性模块)、LogModule(日志模块)、StateMachine(状态机模块)、NodeConfig(配置模块)、LifeCycle(生命周期模块)、Node(节点模块)组成。
Consensus(一致性模块):定义了两个方法:requestVote(投票)、appendEntries(追加日志)。
LogModule(日志模块):最主要是 write、read 方法,其次还有一些为了整个流程的操作而定义的其他方法。
StateMachine(状态机模块):最主要是 apply 方法(将日志提交到状态机中),其次还有一些为了整个流程的操作而定义的其他方法。
NodeConfig(配置模块):配置自己地址跟集群所有地址。
LifeCycle(生命周期模块):定义来 init、destroy 接口。
Node(节点模块):Node 是一个聚合类,它有上面所有的属性,把这些模块聚合起来,表示一个 Raft 节点。它来实现具体的业务逻辑,比如说 handlerRequestVote(选举投票,调用 Consensus 模块)、 handlerAppendEntries(追加日志,调用 Consensus 模块)、处理客户端请求(主要⚠️),重定向等。
3、设计
Raft 论文主要说了三点:选举、日志复制、安全性。前两点主要将集群的选举规则,怎样从 follower -> candidate -> leader 转变。日志复制则讲了日志复制的流程,两阶段分别怎样做。安全性主要论证了为何 Raft 有效,这节主要将证明之类的。光工程实现的话,只需要关注选举、日志复制即可。
详细内容可以参照作者的博客,博客地址如下:http://thinkinjava.cn/2019/01/12/2019/2019-01-12-lu-raft-kv/。写的也算是很清楚的,代码写的也赏心悦目,非常易懂,可以多读。
4、后记
之前读过 zookeeper 的书、源码,窃以为源码的实现还是停复杂的,我当时调试了很多次,后面实在没办法看别人的解析才知道 zab 协议的实现。能上生产的工程代码确实很复杂,以至于我看到选举那块就心力交瘁了,后面日志复制都没注意。所以,我觉得学一个新的东西的时候,如果有那种简化版但又完完整整实现论文的代码,真的非常重要。