文档版本 v3.7-DRAFT 处于 草稿 状态。如需获取最新的稳定版文档,请参阅 v3.6。
etcd API 保证
etcd 是一个一致且持久化的键值存储系统。该键值存储通过 gRPC 服务 暴露。etcd 为分布式系统提供了最强的一致性和持久性保证。本规范列举了 etcd 所提供的 API 保证。
需要考虑的 API
- KV API
- 监听 API
- 租约 API
- 授予(Grant)
- [撤销(Revoke)]
- 保持活跃(Keep alive)
KV API 允许直接读取和操作键值存储。监听 API 允许订阅键值存储的变更。租约 API 允许为键设置生存时间。
KV 和监听 API 不仅可以访问键的最新版本,还可以在连续的历史窗口内访问之前的版本,该窗口受压缩操作的限制。
调用 KV API 会立即生效,而监听 API 的返回存在无界延迟。在正常工作的 etcd 集群中,你通常期望监听事件在发生后约 10 毫秒内出现。然而,并没有严格的上限,在不健康的集群中,事件可能永远不会到达。
KV API
etcd 为所有 KV API 调用确保了持久性和严格串行化。这是分布式事务数据库系统中最强大的隔离保证。
持久性
任何已完成的操作都是持久的。所有可访问的数据也都是已持久化的数据。读取操作永远不会返回尚未持久化的数据。
严格串行化
KV 服务的操作是原子性的,并按照与这些操作真实时间顺序一致的全序执行。这种全序通过版本号(revision)体现。了解更多关于严格串行化的信息。
对于不包含嵌套事务的事务,其操作执行顺序保证与其操作列表中的顺序相同,这意味着事务内的 GET 响应是稳定的。对于包含嵌套事务的事务,执行顺序未作规定。
严格串行化意味着其他一些较弱但更易理解的保证:
原子性
所有 API 请求都是原子性的;操作要么完全完成,要么完全不执行。对于监听请求,单个操作生成的所有事件都会出现在同一个监听响应中。监听永远不会观察到单个操作的部分事件。
线性一致性(Linearizability)
从客户端的角度来看,线性一致性提供了有助于推理的有用属性。以下是一段引自原始论文的清晰描述:线性一致性为并发进程执行的每个操作提供了一种假象,即该操作在其调用和响应之间的某个瞬间立即生效。
例如,考虑一个客户端在时间点 1(t1)完成写入操作。若另一个客户端在 t2(t2 > t1)发起读取请求,则应至少收到在 t1 完成的上次写入的值。然而,该读取操作实际上可能直到 t3 才完成。线性一致性保证了读取返回的是最新的值。如果没有线性一致性保证,那么在读取开始时(t2)有效的值,到 t3 时可能已“过期”,因为在 t2 和 t3 之间可能发生并发写入。
etcd 默认确保所有其他操作的线性一致性。然而,线性一致性是有代价的,因为线性化请求必须经过 Raft 共识过程。为了降低读取请求的延迟并提高吞吐量,客户端可以将请求的一致性模式配置为 serializable,这种模式可能访问相对于法定多数而言已过期的数据,但避免了线性化访问对实时共识的性能开销。
监听 API
监听(Watch)机制对事件提供如下保证:
- 有序性 - 事件按修订版本(revision)排序。如果某个事件在时间上早于已发布的事件,则它永远不会出现在监听流中。对于不包含嵌套事务的事务,生成事件的顺序保证与其操作列表中的顺序一致。对于包含嵌套事务的事务,事件生成顺序未作规定。
- 唯一性 - 同一个事件不会在监听流中出现两次。
- 可靠性 - 在可用的历史窗口内,事件序列不会遗漏任何子序列。如果事件在时间上满足 a < b < c 的顺序,且监听收到了事件 a 和 c,则只要 b 仍在可用历史窗口内,就一定能收到 b。
- 原子性 - 事件列表一定涵盖完整的修订版本。同一修订版本中对多个键的更新不会被拆分到多个事件列表中。
- 可恢复性 - 若监听连接中断,可通过创建一个新的监听来恢复,新监听从断开前最后一个接收到的事件的修订版本之后开始,只要该修订版本仍在历史窗口内即可。
- 可标记性 - 进度通知事件保证在此之前的所有事件都已被成功传递。
etcd 不保证监听操作的线性一致性。用户需要自行验证监听事件的修订版本,以确保与其他操作的正确顺序关系。
租约 API
etcd 提供了租约机制。租约的主要用途是实现分布式协调机制,例如分布式锁。租约机制本身很简单:可以通过授予 API 创建租约,通过 put API 将其附加到键上,通过撤销 API 撤销租约,并根据挂钟时间的生存周期(TTL)自动过期。但是,用户需要注意相关 API 及其使用方式的重要特性,以正确实现分布式协调机制。
etcd 特有定义
操作已完成
当一个 etcd 操作通过共识被提交后,即被视为完成,因此也被认为是“已执行”——即被 etcd 存储引擎永久保存。客户端在收到 etcd 服务器的响应后,便知道操作已完成。需要注意的是,如果操作超时,或客户端与 etcd 成员之间发生网络中断,客户端可能无法确定操作的状态。当发生领导者选举时,etcd 也可能中止操作。在此情况下,etcd 不会向客户端未完成的请求发送 abort 响应。
版本号(Revision)
对键值存储进行修改的 etcd 操作会被分配一个单调递增的修订版本号。事务操作可能会多次修改键值存储,但仅分配一个修订版本号。被该操作修改的键值对的修订版本号与该操作的修订版本号相同。修订版本号可作为键值存储的逻辑时钟:具有较大修订版本号的键值对,其修改时间晚于具有较小修订版本号的键值对;而具有相同修订版本号的两个键值对,则是由同一操作“并发”修改的。