Etcd raftexample 简介
Etcd raft是目前使用最广泛的raft实现,在etcd项目中包含了一个raftexample,来展示怎么使用etcd raft。
这个示例项目基于etcd raft实现了一个分布式KV存储。如上文所言,etcd raft只实现了核心的raft协议,其余的快照、WAL、消息序列化、网络传输等部分都直接使用了etcd 的实现,导致这个example特别不好读。raftexample 包含了三个组件:基于Raft的key value store,一个REST API Server,以及基于etcd raft实现的Raft Consensus Server。后文将逐一介绍这三个组件。
Bug Fix
首先需要说明的是,官网当前(as of 2018/12/30)的实现,在处理对快照的处理方面是有严重bug的,具体有两点:
- 如果server启动时存在快照的话,server会读取这个快照,然后卡在一个循环里面不返回,阻塞了后续REST API Server的启动,导致无法响应客户端请求。
- 假使修复上面的bug,该实现还存在一个逻辑错误:它先回放WAL日志,然后再加载快照,跟正确的行为刚好相反。
Github上有人针对这些问题提过issue:
- raftexample may never serve http request after loading snapshots
- raftexample: restore or overwrite kvstore after replaying has done?
我原想着fix这几个问题,但是苦于很多细节自己都没弄明白,然后发现有人提了一个patch contrib/raftexample: fix backend storage loading from a snapshot 。一看作者是Yandex的毛子,感觉靠谱,把补丁拿下来打上再运行,符合预期,perfect。因此后文的分析都基于这个打过patch的版本,地址为https://github.com/4179e1/etcd/tree/19e567a1362d1c97749ea2b568040ac57c39fc29/contrib/raftexample
冷知识 – 如何在git上下载一个patch文件?在Pull Request的链接上加上.patch,如上文的 https://github.com/etcd-io/etcd/pull/9918.patch
这件事告诉我们,raftexample的细节上未必经得起推敲,所以遇到疑惑的地方,不妨大胆的怀疑吧。看看这个怪异的实现,同样函数同样的参数执行两次,一次直接返回,另一次作为goroutine一直在后台接受请求。
func newKVStore(snapshotter *snap.Snapshotter, proposeC chan<- string, commitC <-chan *string, errorC <-chan error) *kvstore {
s := &kvstore{proposeC: proposeC, kvStore: make(map[string]string), snapshotter: snapshotter}
// replay log into key-value map
s.readCommits(commitC, errorC)
// read commits from raft into kvStore map until error
go s.readCommits(commitC, errorC)
return s
}
打完补丁后就顺眼很多了
func newKVStore(snapshotter *snap.Snapshotter, proposeC chan<- string, commitC <-chan *string, errorC <-chan error) *kvstore {
s := &kvstore{proposeC: proposeC, kvStore: make(map[string]string), snapshotter: snapshotter}
// read commits from raft into kvStore map until error
go s.readCommits(commitC, errorC)
return s
}
Raftexample 功能
- Key Value的增加/修改(HTTP PUT),查找(HTTP GET),对了,没有删除
- 支持单节点和多节点
- 支持节点的动态配置,增加一个节点(HTTP ADD),删除一个节点(HTTP DELETE)
- 集群容错,在对多故障N/2 -1 个节点的情况下能正常提供对外服务
具体使用请参考官方手册
下面来逐一介绍Raftexample的三个组件
Key Value Store
REST Server
Raft Server