ETCD是Go生态圈中的分布式K/V实现,它背后是第一个生产级别的Raft协议实现,一些分布式系统中,如TiKV(Rust实现)等,也借鉴了它的Raft协议实现。
最初ETCD的定位仅仅是一个高可用的配置管理服务,在*NIX系统中“/etc”目录用以存储单机系统配置,而一个分布式(Distributed)的配置管理服务(/etc)就是ETCD。随着越来越广泛的应用,ETCD V3已经演变为一个通用K/V系统。
结合ETCD历史版本中存储系统的优化,本文系统介绍了ETCD中的存储系统实现。弄清楚ETCD背后分布式存储的实现不仅对故障排除、日常运维助益颇多,也可以为分布式存储的实现提供思路。
Raft模块原理简介
Raft模块承担了集群管理和指令决策、执行,以及相应的存储管理层,即WAL(Write-Ahead-Log)和快照(Snapshot)。Fig 1.1中从单个节点的角度看Raft模块的原理。
Fig 1.1 简化的Raft协议模型
Raft模块可以从功能上分成三部分:
· 共识模块(Consensus Module):接收和处理指令
· Log: 存储历史指令,和当前状态机的状态(Commit到哪一条等)
· State Machine: 集群最新状态,ETCD里面主要就是数据库
客户端向集群发起一次写操作的数据流大致涉及4个步骤:
1. 客户端发起一个需要和集群一起决策的指令,如发起一个写请求
2. 将指令持久化到WAL(Write-Ahead-Log),共识模块会更新Log状态(如Committed等信息)
3. 当指令在集群中达成了一致(Committed),就需要在状态机中执行(Apply)这条指令,状态机主要就是一个内存中的数据库
4. 节点向客户端返回更新操作的结果
Raft协议层采用消息模型实现,无论是对配置(集群的节点)还是数据进行的修改,最终都会传入Raft模块与整个集群一起决策,决策过程就是一些gRPC封装的请求、响应的过程,每个请求或响应都可能改变Raft状态机的状态,后文中会详细介绍。