在分布式文件存储中,我们通常会面临集群选主,配置共享和节点状态监控的问题。通过 etcd(基于 Raft 协议))可以实现超大规模集群的管理,以及多节点的服务可靠性。今天,我们就聊聊 etcd 在分布式存储中的具体应用。
什么是 etcd ?
etcd 是由 CoreOS 公司开发的一个开源的分布式 KV 存储,主要用于服务发现、共享配置以及一致性保障。etcd 的灵感来自于 ZooKeeper 和 Doozer,但它更侧重以下几点:
- 简单:安装配置简单,支持 curl 方式的用户 API (HTTP+JSON)。
- 安全:可选支持 SSL 客户端证书验证。
- 快速:根据官方提供的 benchmark 数据,单实例支持每秒 1w+ 写操作。
- 可靠:采用 Raft 算法,实现分布式系统数据的可用性和一致性。
为什么采用 etcd ?
谈到 etcd,我们不免会与 Zookeeper(以下简称 ZK)或 Consul 进行比较,Consul 的可靠性和稳定性还需要时间来验证(项目发起方自己也并未使用);ZK 和 etcd 都是顺序一致性的(满足 CAP 的 CP),这就意味着无论我们访问任意节点,都将获得最终一致的数据视图。对比 ZK, etcd 具有以下优势:
- 一致性:etcd 使用 Raft 协议,简单易懂,而 ZK 使用 ZAB(类 paxos 协议),该协议以复杂著称,尤其对初学者来说。
- 运维方面 :etcd 比 ZK 更容易运维。
- 项目活跃度 :etcd 社区比较活跃,代码贡献者超 700 人,目前一直在更新。而 ZK 社区相比活跃度不是那么高,代码贡献者 170 多人,版本很久没有更新。
- 接口方面:etcd 提供了 http + json,grpc 接口,支持跨平台。而 ZK 需要使用其专属客户端。
- 安全性:etcd 支持 https 访问,ZK 在这方面缺失。
etcd 架构及工作原理
etcd 架构图
- 网络层 HTTP Server:用于处理用户发送的 API 请求以及其它 etcd 节点的同步与心跳信息请求。
- Raft 模块:Raft 强一致性算法的具体实现,是 etcd 的核心。
- Store 模块:涉及 KV 存储、WAL 文件、Snapshot 管理等,用户处理 etcd 支持的各类功能的事务,包括数据索引节点状态变更、监控与反馈、事件处理与执行,是 etcd 对用户提供的大多数 API 功能的具体实现。
- 副本状态机:这是一个抽象的模块,状态机的数据维护在内存中,定期持久化到磁盘,每次写请求都会持久化到 WAL 文件,并根据写请求的内容修改状态机数据。
etcd 工作原理
etcd 集群是一个分布式系统,由多个节点相互通信构成整体对外服务。每个节点都存储了完整的数据,并且通过 Raft 协议保证每个节点维护数据的一致性。在 Raft 协议中,有一个强 leader,由它全权负责接收客户端的请求命令,并将命令作为日志条目复制给其他服务器,在确认安全后,将日志命令提交执行。当 leader 故障时,会选举产生一个新的 leader。在强 leader 的帮助下,Raft 将一致性问题分解为三个子问题:
1、Leader 选举:当已有的 leader 故障时必须选出一个新的 leader。
2、日志复制:leader 接受来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与 leader 保持一致。
3、安全 safety 措施:通过一些措施确保系统的安全性,如确保所有状态机按照相同顺序执行相同命令的措施。
etcd 在分布式存储中的应用
对于分布式存储来说,需要存储提供一些公用的配置信息,提供统一的集群视图。存储具备读写速度快,支持高可用且部署简单。此时,就需要使用到 etcd 了。
分布式存储节点角色一般有:mgr,mds 和 oss。其中 mgr 是集群的管理节点,提供共享配置和维护集群主从视图,mds 存储集群的元数据,oss 则用来存储用户数据。
将 etcd 纳入分布式存储内部的架构图如下所示:
利用 etcd lease 机制为分布式存储选主
etcd lease 机制能够确保一个 etcd 集群中的 key 拥有一种临时性的特征,被指定某个 lease 的 key 只能在集群中存活某一段时间,时间到了就会被集群自动删除。这段存活时间叫做 TTL (Time To Live)。
mgr 节点之间可以竞争 etcd 中同一个拥有 lease 属性的 key,比如: “/dfs/mgr/master”。当一个 mgr 节点竞争到这个 key,他就成为了mgr 主,同时其他节点就成为了 mgr 从。mgr 节点存活期间,定期给自己的 lease 续租,就可以一直保持自己的 mgr 主身份。一旦 mgr 主发生异常(比如宕机),过了 TTL 时间后,其持有的 key 就会被自动删除。此时,mgr 从节点发现 “/dfs/mgr/master” key 不存在后,就会重新竞争 mgr 主,重新获得此 key 的 mgr 升级为新的 mgr 主。
利用 etcd watch 机制为组件探活
etcd 提供了watch 机制,客户端 watch 了一系列 key,当这些被 watch 的 key 数据发生变化时,就会产生相应的事件通知客户端,相关的事件类型有:set, delete, update, create, compareAndSwap, compareAndDelete。
在 mds 服务启动时,向 etcd 注册自己的 ip(例如 /dfs/mds_nodes/, /dfs/mds_nodes/...),该 key 拥有 lease 属性。一旦 mds 服务异常,该 mds 的 ip 就会从 etcd 中 /dfs/mds_nodes 自动删除。这样,我们在 mgr 主节点启动监听 /dfs/mds_nodes 目录,就会得到某个 mds 上线和下线的事件通知,并且可以对 mds 相应的状态做标记,如果是 mds 主下线,则立即执行 mds 主从切换。
oss 同 mds 一样,监听的的目录变为 /dfs/oss_nodes。
通过 etcd 的 watch 机制,我们能快速地感知到 mds 或 oss 故障,进行 mds 或 oss 的主从切换(时间控制在 10 秒以内),从而保证客户端业务不受影响。
利用 etcd 做配置共享
etcd 高可用特性和快速读写,为我们使用配置共享提供了基础。我们把 mgr,mds,oss 的配置信息写入 etcd 集群中,各个组件从 etcd 集群中读取相应配置即可。
etcd 集群节点个数和性能
据 etcd 官网介绍,etcd V3 版本最高可以提供每秒 1 万次写入操作。但是随着 etcd 节点个数的增加,其写入性能会逐渐降低,所以我们一般采用 3 节点,5 节点或 7 节点部署 etcd 集群。大家可能会问:为什么不采用偶数节点,比如 4 节点,6 节点呢?因为 etcd 采用 Raft 协议,是 quorum 机制,要求半数以上节点在线。所以 4 节点的容错性和 3 节点是等价的,都是只能允许一个节点故障。但是多一个节点,一方面写入性能不如 3 节点,另一方面偶数节点在 etcd 内部选主时,有可能造成某一轮两个 candidate 节点获取的选票一致,从而延长选主时间。
etcd 支持 IPv6 协议
对于某些用户,为了安全,不提供 IPv4 地址,主机只有 IPv6 地址。这时候,etcd 的 IPv6 就发挥作用了。我们用实例展示,etcd 如何配置 IPv6 进行节点间通信,如下图所示(etcd 单节点集群):
该实例的 IPv6 地址为 2022::24, 使用时,用 [] 将 IPv6 地址括起来即可。需要注意的是该 IPv6 地址只能使用 Scope global 类型,不能使用 Scope link 类型,否则,在启动 etcd 服务时,会报 bind 地址无效错误。
据统计,目前至少有 CoreOS、 Kubernetes、Cloud Foundry, 以及在 Github 上超过 500 个项目在使用 etcd。