为什么叫etcd
“etcd”这个名字源于两个想法,即 unix “/etc” 文件夹和分布式系统”d”istibuted。 “/etc” 文件夹为单个系统存储配置数据的地方,而 etcd 存储大规模分布式系统的配置信息。因此,”d”istibuted 的 “/etc” ,是为 “etcd”。
etcd 以一致和容错的方式存储元数据。分布式系统使用 etcd 作为一致性键值存储,用于配置管理,服务发现和协调分布式工作。使用 etcd 的通用分布式模式包括领导选举,分布式锁和监控机器活动。
术语
Node / 节点
Node/节点 是 raft 状态机的一个实例。
它有唯一标识,并内部记录其他节点的发展,如果它是leader。
Member / 成员
Member/成员是 etcd 的一个实例。它承载一个 node/节点,并为client/客户端提供服务。
Cluster / 集群
Cluster/集群由多个 member/成员组成。
每个成员的节点遵循 raft 一致性协议来复制日志。集群从成员中接收提案,提交他们并应用到本地存储。
Peer / 同伴
Peer/同伴是同一个集群中的其他成员。
Proposal / 提议
提议是一个需要完成 raft 协议的请求(例如写请求,配置修改请求)。
Client / 客户端
Client/客户端是集群 HTTP API的调用者。
注: 对于V3,应该包括 gRPC API。
Machine / 机器 (弃用)
在 2.0 版本之前,在 etcd 中的成员备选。
KV API 保证
etcd 是一致而持久的键值存储,带有微事务(mini-transaction)。键值对存储通过 KV API暴露。etcd 力图为分布式系统获取最强的一致性和持久性保证。
读 APIs
- range
- watch
写 APIs
- put
- delete
联合 (读-改-写) APIs
- txn
etcd 明确定义
操作完成
当 etcd 操作通过一致同意而提交时,视为操作完成,并且因此”执行过” — 永久保存 — 被etcd 存储引擎。当客户端从etcd服务器接收到应答时,客户端得知操作已经完成。注意,如果客户端和 etcd 成员之间有超时或者网络中断,客户端可能不确定操作的状态。当有 leader 选举时,etcd 也可能中止操作。在这个事件中,etcd 不会发送 abort 应答给客户端的未完成的请求。
revision/修订版本
修改键值存储的 etcd 操作被分配有一个唯一的增加的修订版本。事务操作可能多次修改键值存储,但是只分配一个修订版本。被操作修改的键值对的 revision 属性和操作的 revision 有同样的值。修订版本可以用来给键值存储做逻辑时间。有较大修订版本的键值对在有较小修订版本的键值对之后修改。两个拥有相同修订版本的键值对是被一个操作同时修改。
提供的保证
原子性
所有 API 请求都是原子的; 操作或者完整的完成,或者完全不。对于观察请求,一个操作生成的所有事件将在一个观察应答中。观察绝不会看到一个操作的部分事件。
一致性
所有 API 调用确保 顺序一致性, 分布式系统可用的最强的一致性保证。不管客户端的请求发往哪个etcd成员,客户端以同样的顺序读取相同的事件。如果两个成员完成同样数量的操作,这两个成员的状态是一致的。
对于观察操作,etcd保证所有成员对于同样的修订版本返回同样的key返回同样的值。对于范围操作,etcd有类似的线性一致性访问保证;
所谓强一致性就是:任何时刻任何用户或节点都可以读到最近一次成功提交的副本数据。
因为,仅仅通过Quorum机制无法确定最新已经成功提交的版本号。
比如,提交一份数据成功提交后(已经写入W=3份),尽管读取3个副本时一定能读到新提交的数据,如果刚好读到的是3份一样最新提交的数据,则此次读取的数据是最新成功提交的数据,因为w=3,而此时也刚好读到了3份。如果读到的是一份新数据两份就数据呢,则无法确定是一个成功提交的版本,还需要继续再读,直到读到新数据的副本达到3份为止,这时才能确定是已经成功提交的最新的数据。
Quorum机制是“抽屉原理”的一个应用。定义如下:假设有N个副本,更新操作后在实现预期的副本数量(W)更新成功之后,才认为此次更新操作成功。称成功提交的更新操作对应的数据为:“成功提交的数据”。对于读操作而言,至少需要读(R)个副本才能读到此次更新的数据。其中,W+R>N ,即写入和读取有重叠。
假设系统中有5个副本,W=3,R=3。初始时数据为(V1,V1,V1,V1,V1)--成功提交的版本号为1
当某次更新操作在3个副本上成功后,就认为此次更新操作成功。数据变成:(V2,V2,V2,V1,V1)--成功提交后,版本号变成2
因此,最多只需要读3个副本,一定能够读到V2(此次更新成功的数据)。而在后台,可对剩余的V1 同步到V2,而不需要让Client知道。
和所有分布式系统一样,对etcd来说确保强一致性是不可能的。etcd不保证它会给读操作返回在任意集群成员上可以访问的”最近”(most recent)的值(可理解最新提交的值)
隔离
etcd确保串行化隔离,这是在分布式系统中可用的最高隔离级别。读操作从不查看任何中间数据。
持久性
任何完成的操作都是持久的。所有可访问的数据也都是持久的数据。读从来不会返回没有持久化的数据。
线性一致性
线性一致性(也被称为 Atomic Consistency 或者 External Consistency)是介于 strict consistency/严格一致性和 sequential consistency/顺序一致性之间的一致性级别。
对于线性一致性,假设每个操作从宽松的已同步全局时钟获取时间戳。
当且仅当操作总是像按顺序执行一样完成,并且每个操作似乎按程序指定的顺序完成时,才线性化操作。
同样的,如果操作的时间戳发生在其他操作前,这个操作在顺序上必须也发生在其他操作前。
例如,考虑客户端在时间点1(t1)完成一个写操作。客户端在t2 (t2 > t1)发送的读请求应该收到至少在上一次在t1时间点完成的写之后最近的值。然后,读可能实际在t3完成,而返回值,在t2时刻开始读,可能在t3时刻已经不再新鲜。
对于观察操作 etcd 不保证线性一致性。期望用户验证观察应答的修订版本来确保正确顺序。
对于所有其他操作 etcd 默认保证线性一致性。线性一致性会带来开销,无论如何,因为线性化请求必须通过Raft一致性过程。为了获得读请求更低的延迟和更高的吞吐量,客户端可以配置请求的一致性模型为 serializable ,这可能访问的数据不是最新的(with respect to quorum),但是移除了线性化访问时依赖活动一致性的性能损失。
认证变更
v3 协议使用 gRPC 传输而不是像 v2 这样的 RESTful 接口。
v3 auth具有基于连接的身份验证,而不是v2的每次请求的速度较慢的认证。
每连接认证,而不是每请求
- 基于用户ID + 密码的认证,实现为 gRPC API
- 在认证政策修改之后,认证必须刷新
- 功能应该和v2一样简单
v3 提供扁平键空间,和v2的目录结构不同。提供权限检查,如间隔匹配(as interval matching)
- 应该提供比v2认证更强的一致性保证
主要需要更改
客户端必须在发送被验证的请求之前创建仅用于认证的专用连接
添加权限信息(用户 ID 和 合法 revision) 到 Raft 命令 (etcdserverpb.InternalRaftRequest)
在状态机层做每个请求的权限检查,而不是在 API 层
权限元数据一致性
认证的元数据也应该在存储中存储和管理,该存储被etcd的Raft协议控制,和其他在etcd中的数据一样。要求不牺牲整个etcd集群的可用性和一致性。如果读取或写入元数据(例如权限信息)需要每个节点(超过法定人数)的同意,则单节点故障会让整个集群停止。要求所有节点立即同意意味着,如果任意集群成员宕机,即使群集具有可用的法定人数,检查普通的读/写请求也无法完成。 这种全场一致方案最终会降低集群的可用性; 从raft而来的基于法定人数的共识就足够了,因为合约遵循一致的顺序。
和 etcd 交互
用户通常通过设置或者获取键的值来和 etcd 交互。这一节描述如何使用 etcdctl 来操作, etcdctl 是一个和 etcd 服务器交互的命令行工具。这里描述的概念也适用于 gRPC API 或者客户端类库 API。
默认,为了向后兼容 etcdctl 使用 v2 API 来和 etcd 服务器通讯。为了让 etcdctl 使用 v3 API 来和etcd通讯,API 版本必须通过环境变量 ETCDCTL_API 设置为版本3。
export ETCDCTL_API=3
gRPC网关
为什么用 grpc-gateway
etcd v3 使用 gRPC 作为它的消息协议。etcd 项目包括基于 gRPC 的 Go client 和 命令行工具 etcdctl,通过 gRPC 和 etcd 集群通讯。对于不支持 gRPC 支持的语言,etcd 提供 JSON 的 grpc-gateway。这个网关提供 RESTful 代理,翻译 HTTP/JSON 请求为 gRPC 消息。
使用 grpc-gateway
网关接受 etcd 的 protocol buffer 消息定义的 JSON mapping 。注意 key 和 value 字段被定义为 byte 数组,因此必须在 JSON 中以 base64 编码。下面例子使用 curl,但是任何 HTTP/JSON 客户端都可以如此工作。
请求大小限制
etcd 被设计用于处理小型的键值对,典型如元数据。更大的请求可以工作,但可能会增加其他请求的延迟。目前,etcd 保证支持不超过 1MB 数据的 RPC 请求。将来,大小限制可能会松动或可配置。
储存大小限制
默认存储大小限制是 2GB, 可以通过 --quota-backend-bytes 标记配置; 最大支持 8GB.