etcd raft

1 环境

https://github.com/etcd-io/etcd/releases/tag/v3.5.18

raftexample 是 etcd 提供的一个使用 etcd raft 共识算法库的示例。raftexample 最终实现了一个对外提供 REST API 的分布式键值存储服务。

2 代码结构

raftexample 的结构非常简洁,其主要文件如下:

  • main.go: 负责 raft 模块,httpapi 模块和 kvstore 模块之间的交互方式的组织;

  • raft.go: 提供网络基础通信、raft 协议推进执行能力。

  • httpapi.go: 向客户端 client 提供服务,主要提供 Get、Put、Post、Delete 接口服务。这三个服务的作用分别是检索KV、存储KV、新增 raft 节点、删除 raft 节点。

  • kvstore.go: 提供持久化存储功能。raft 协议本身并不提供存储能力,所以所有的 KV 最终的归属是这个kvstore。

  get  post          delete  put
   |     |              |     |
   |     |              |     |
 +-V-----V--------------V-----V--+
 |        HTTP Service           |
 +------+------------------------+
        |                         
        |                         
 +------V------+ ---> +----------+
 |   KVStore   |      | raftNode |
 +-------------+ <--- +----------+
 
 首先 client 向 raft 节点发送请求,假设调用 Put 方法,存储一个新的 kv。
 节点收到这个请求之后,将 KV 对传递给 kvstore。
 kvstore 拿到 kv 之后,并不急着将其进行持久化存储,而是将这个 kv 投递给 raftNode,
 通过 raftNode 对这个 kv 进行决议,决议通过后,再将这个 kv 回送给 kvstore。
 最后 kvstore 进行持久化存储。

3 代码实现

3.1 http service

http service 的实现比较简单,它自定义了 httpKVAPI 结构体,其重写了 ServeHTTP 方法。然后通过serveHttpKVAPI 方法启动服务。需要注意的是,其内部持有 kvstore 对象,Get 方法和 Put 方法分别调用了 kvstore 的 Propose 方法和 Lookup 方法。

3.2 kvstore

type kvstore struct {
    proposeC    chan<- string     // channel for proposing updates
    mu          sync.RWMutex
    kvStore     map[string]string // current committed key-value pairs
    snapshotter *snap.Snapshotter
}

kvstore 的定义中,kvStore 是存储结构,用了简单的 map 进行存储。mu负责多线程同步。除此之外,还有两个非常关键的属性,分别是 proposeC 管道和 snapshotter。这个结构说明,如果要实现一个kvstore,除了基本的存储结构之外,至少还需要一个管道和一个 snapshotter。

 +----------------------------------+
 |          HTTP Service            |
 +---------+------------------------+
        |
        |
 +------V------+      +-------------+
 |             |      |             |
 | +---------+ |      |             |
 | |proposeC +------->|             |
 | +---------+ |      |             |
 |             |      |             |
 |             |      | +---------+ |
 |             |<-------+ commitC | |
 |             |      | +---------+ |
 |             |      | +---------+ |
 |             |<-------+  errorC | |
 |             |      | +---------+ |
 |             |      |             |
 |             |      |             |
 |   KVStore   |      |  raftNode   |
 +-------------+      +-------------+
 

kvstore 和raftNode 之间使用了三个管道,分别是 proposeC(提议)、commitC、errorC。

  1. kvstore使用proposeC将从http service传来的数据提交给raftNode;

  2. raftNode将通过决议的数据,从commitC回送给kvstore。异常信息通过errorC进行传输。

3.3 raftNode

Last updated