3. etcd 数据模型:键值存储逻辑、版本号(revision)、租约(lease)、watch机制、MVCC多版本并发控制
etcd 是一个强一致性的分布式键值存储系统,其底层数据模型围绕 MVCC(多版本并发控制) 构建。理解这一模型是掌握备份、恢复与蓝绿发布回滚策略的基础。本章将深入剖析 etcd 的核心数据组件及其交互逻辑。
3.1 键值存储逻辑与 MVCC 架构
etcd 的存储层并非简单的覆盖式写入,而是采用 追加写(Append-Only) 的方式。每次对键的修改都会生成一个新的版本记录,旧版本数据不会被立即删除,而是保留以供历史查询或 Watch 机制使用。这种设计即为 MVCC。
核心思想: 写操作不原地修改数据,而是追加一个新版本。读操作可以读取指定版本的数据,从而实现无锁并发读取。
下图展示了 etcd 的 MVCC 存储架构,包含从客户端请求到后端持久化的完整链路:
3.2 版本号(revision)
版本号是 etcd MVCC 的核心元数据。它是一个全局单调递增的整数,每次事务提交时自增 1。每个键值对在创建或更新时,都会关联一个 revision。
| 概念 | 说明 | 示例 |
|---|---|---|
| 全局 revision | 集群级别的逻辑时钟,每次写操作(Put/Delete/Txn)后递增。 | 初始为 1,第一次写入后变为 2。 |
| 键的版本(version) | 某个键被修改的次数,从 1 开始计数。 | 键 /app/config 被修改 3 次,version 为 3。 |
| 创建 revision | 该键首次创建时的全局 revision。 | 创建时 revision 为 10,则 create_revision = 10。 |
| 修改 revision | 该键最近一次修改时的全局 revision。 | 最近修改时 revision 为 25,则 mod_revision = 25。 |
备份与恢复中的关键作用: 在执行增量备份时,可以通过记录当前
revision 作为快照点。恢复时,只需重放该 revision 之后的变更日志,即可实现精确的增量恢复。
3.3 租约(Lease)
租约是 etcd 中用于实现 键的自动过期与心跳保活 的机制。一个租约有一个 TTL(生存时间),关联到该租约的所有键会在租约过期时被自动删除。
- 创建租约: 客户端通过
LeaseGrant创建一个租约,指定 TTL(单位:秒)。 - 关联键: 执行 Put 操作时,通过
WithLease选项将键绑定到指定租约 ID。 - 续约(KeepAlive): 客户端定期发送心跳,刷新租约的 TTL,防止键被自动删除。
- 租约过期: 如果租约到期且未续约,etcd 会异步删除该租约下所有关联的键。
蓝绿发布场景注意: 如果使用租约管理服务注册信息(如
/services/blue),在回滚时需要确保旧版本的租约仍然有效,或者手动恢复租约绑定,否则服务实例可能被 etcd 自动摘除。
3.4 Watch 机制
Watch 是 etcd 实现 事件驱动 的核心能力。客户端可以监听某个键或某个前缀(prefix)的变更事件,当数据发生变化时,etcd 会实时推送事件通知。
Watch 的工作流程如下:
- 创建 Watch: 客户端发起 Watch 请求,指定监听的键或前缀,以及起始 revision。
- 事件推送: 当被监听的键发生 Put、Delete 操作时,etcd 将事件(包含 key、value、type、revision)推送给客户端。
- 历史事件回放: 如果指定了起始 revision,etcd 会从该 revision 开始,将历史事件按顺序推送给客户端,确保不丢失变更。
- 长连接维持: Watch 基于 gRPC 流式连接,客户端无需轮询,etcd 主动推送。
下图展示了 Watch 机制中客户端与 etcd 服务端的交互流程:
3.5 多版本并发控制(MVCC)总结
etcd 的 MVCC 实现将上述组件有机整合,形成了一套高效、可靠的存储引擎。下表总结了各组件在 MVCC 中的角色:
| 组件 | MVCC 中的角色 | 对备份/回滚的影响 |
|---|---|---|
| Revision | 全局版本号,标识数据变更的顺序与快照点。 | 增量备份的断点标记;回滚时指定目标 revision。 |
| Lease | 管理键的生命周期,与 MVCC 版本独立。 | 备份需保留租约元数据;回滚时需重建租约绑定。 |
| Watch | 基于 revision 的事件流,支持增量变更感知。 | 用于实时同步或触发回滚后的补偿操作。 |
| Bbolt + Buffer | 持久化存储引擎,Buffer 暂存未提交的写入。 | 备份需确保 Buffer 已刷盘(Flush),避免数据丢失。 |
实践要点: 在蓝绿发布场景中,可以利用 Watch 机制监听配置键的变更,当检测到异常变更时,通过指定
revision 进行回滚操作。同时,租约的 TTL 设置需要大于回滚操作的预期耗时,避免服务实例被意外摘除。