// 负责对客户端请求的处理 相当于Spring MVC的Controller 实现了Handler 这个接口就一个方法ServeHTTP 客户端有请求进来后ServeHTTP方法会被回调 type httpKVAPI struct { // 在httpKVAPI组件中组合了kvstore 一旦有客户端请求过来就可以操作kvstore组件 store *kvstore confChangeC chan<- raftpb.ConfChange }
1.2 客户端读
1 2 3 4 5 6 7
case http.MethodGet: // 客户端get数据 if v, ok := h.store.Lookup(key); ok { w.Write([]byte(v)) } else { http.Error(w, "Failed to GET", http.StatusNotFound) }
1.3 客户端写
1 2 3 4 5 6 7 8 9 10 11 12 13 14
case http.MethodPut: // 客户端put数据 v, err := io.ReadAll(r.Body) if err != nil { log.Printf("Failed to read on PUT (%v)\n", err) http.Error(w, "Failed on PUT", http.StatusBadRequest) return } // 请求转给kvstore 还没有真正的进行存储 先封装成键值对 然后通过propose channel通知raft进行日志决议和提交 再通过commit channel通知给kvstore进行存储 h.store.Propose(key, string(v))
// Optimistic-- no waiting for ack from raft. Value is not yet // committed so a subsequent GET on the key may return old value w.WriteHeader(http.StatusNoContent)
2 etcd
在etcd集群中每个节点承担两个功能
既是raft的一个节点,需要进行raft协议的通信
又是数据库的服务端,需要接收客户端的读写请求
2.1 raft通信
1 2 3 4
// 初始化集群间通信TCP连接 if e.Peers, err = configurePeerListeners(cfg); err != nil { return e, err }
2.2 数据库服务端
1 2 3 4
// 初始化集群节点开放给客户端的TCP连接 if e.sctxs, err = configureClientListeners(cfg); err != nil { return e, err }