2. etcd 数据模型与存储:key-value 存储模型、MVCC 机制、数据目录结构、WAL 与 snapshot

etcd 作为分布式键值存储系统,其底层数据模型与存储引擎的设计直接决定了集群的可靠性、读写性能以及灾难恢复能力。理解 etcd 如何组织数据、管理多版本并发控制、维护预写日志与快照,是制定备份策略和优化 RPO 的基础。

2.1 Key-Value 存储模型

etcd 采用扁平的 key-value 模型,所有数据以二进制字节数组形式存储。Key 按字典序排序,支持前缀扫描与范围查询。与关系型数据库不同,etcd 不提供表、行、列的概念,而是将数据组织为有序的键值映射。

特性 说明
Key 类型 字节数组([]byte),最大 1 MB
Value 类型 字节数组([]byte),最大 1 MB
排序规则 按 Key 的字节序(byte-wise)升序排列
版本管理 每个 Key 维护多个版本,通过 revision 标识
租约关联 Key 可绑定租约(Lease),租约过期自动删除 Key
运维提示: 备份时需注意 Key 的租约状态。如果备份后恢复,租约时间可能已过期,导致 Key 被自动清理。建议在恢复后检查租约有效期,必要时重新创建租约。

2.2 MVCC 机制与 Revision

etcd 使用多版本并发控制(MVCC)来支持历史版本查询与事务隔离。每个修改操作(Put、Delete)都会生成一个全局递增的 revision(主版本号),用于标识数据变更的顺序。

  • 全局 revision: 集群内单调递增,每次事务提交时递增 1。
  • Key 的版本(version): 单个 Key 的修改次数,从 1 开始递增。
  • 历史版本保留: 默认保留所有历史版本,可通过 --auto-compaction-retention 设置自动压缩策略。

MVCC 核心流程:

  1. 客户端发起 Put(key, value) 请求。
  2. etcd 分配新的全局 revision(如 1001)。
  3. 将 (revision, key, value) 写入底层存储(boltdb)。
  4. 更新 Key 的当前版本号(version +1)。
  5. 旧版本数据仍保留,直到被压缩(compaction)清理。
etcd MVCC 写入流程 客户端 API 层 MVCC 模块 boltdb 步骤说明: ① 客户端发送 Put(key, value) 请求到 API 层。 ② API 层将请求转发给 MVCC 模块,分配全局 revision(如 1001)。 ③ MVCC 模块将 (revision, key, value) 写入 boltdb 事务。 ④ boltdb 将数据持久化到磁盘,更新 Key 的当前版本号。 ⑤ 旧版本数据保留在 boltdb 中,等待后续压缩清理。 ⑥ 返回成功响应给客户端,携带当前 revision。

2.3 数据目录结构

etcd 的数据目录通常位于 --data-dir 指定的路径下(默认 ${name}.etcd/)。理解目录结构有助于定位备份文件与诊断问题。

${data-dir}/
├── member/
│   ├── snap/                # 快照文件目录
│   │   └── 0000000000000001-0000000000000001.snap
│   ├── wal/                 # 预写日志目录
│   │   ├── 0000000000000000-0000000000000000.wal
│   │   └── 0.tmp            # 临时 WAL 文件(写入中)
│   └── backend/             # boltdb 数据库文件
│       └── db               # 主存储文件(包含所有 key-value 数据)
├── wal/                     # 软链接到 member/wal(旧版本兼容)
└── snap/                    # 软链接到 member/snap(旧版本兼容)
文件/目录 作用 备份关注点
member/snap/ 存储 etcd 快照文件(.snap),用于快速恢复 定期备份快照文件,作为 RPO 优化基础
member/wal/ 存储预写日志(.wal),记录所有写操作 WAL 文件用于增量恢复,需保留足够历史
member/backend/db boltdb 数据库文件,存储所有当前和历史数据 备份时需确保文件一致性(建议使用 etcdctl snapshot save)
重要: 直接复制 member/backend/db 文件进行备份是不安全的,因为 boltdb 在运行时可能处于不一致状态。必须使用 etcdctl snapshot save 或 etcd 内置的 snapshot API 创建一致性快照。

2.4 WAL(预写日志)

WAL(Write-Ahead Log)是 etcd 保证数据持久性的核心机制。所有写操作在应用到 boltdb 之前,必须先写入 WAL 文件。WAL 文件按段(segment)组织,每个段文件大小默认为 64 MB。

  • 写入顺序: 先写 WAL,再写 boltdb。如果 etcd 崩溃,重启时通过回放 WAL 恢复未持久化的数据。
  • 文件命名: {起始索引}-{长度}.wal,例如 0000000000000000-0000000000000000.wal。
  • WAL 记录类型: 包括普通写入记录、元数据记录、快照记录等。
  • WAL 压缩: 创建快照后,之前的 WAL 文件可以被安全删除(由 etcd 自动管理)。

WAL 在备份恢复中的角色:

  • 快照文件提供某一时刻的全量数据。
  • WAL 文件提供快照之后的所有增量变更。
  • 恢复时:先加载快照,再回放快照之后的 WAL 记录,达到最新一致状态。
  • RPO 优化目标:通过高频快照 + 保留足够 WAL,将数据丢失窗口控制在秒级。

2.5 Snapshot(快照)

快照是 etcd 在某个时间点的全量数据副本,用于加速恢复和压缩 WAL。etcd 支持两种快照机制:

快照类型 触发方式 文件格式 用途
自动快照 WAL 文件数量达到阈值(默认 10000 条记录) .snap 文件 内部压缩 WAL,加速重启恢复
手动快照 etcdctl snapshot save 命令 .db 文件(实际是 boltdb 副本) 备份、迁移、灾难恢复
WAL 与 Snapshot 协同工作流程 时间轴 Snapshot T1 Snapshot T2 Snapshot T3 WAL 段 1 WAL 段 2 WAL 段 3 恢复流程: 加载最新快照(如 T2)→ 回放 T2 之后的所有 WAL 记录(WAL 段 2 及之后)→ 达到最新一致状态。

2.6 数据压缩与历史版本清理

随着时间推移,MVCC 历史版本会占用大量磁盘空间。etcd 通过压缩(compaction)机制清理旧版本数据。

  • 自动压缩: 通过 --auto-compaction-retention 设置保留时间(如 1h),etcd 定期删除超过保留期的历史版本。
  • 手动压缩: 使用 etcdctl compaction <revision> 手动触发压缩。
  • 碎片整理: 压缩后 boltdb 文件不会立即缩小,需执行 etcdctl defrag 回收磁盘空间。
备份策略影响: 如果压缩间隔过短,历史版本被快速清理,可能导致基于 WAL 的增量恢复失败(因为需要的 WAL 记录已被删除)。建议在备份策略中协调压缩参数与 WAL 保留策略,确保快照 + WAL 能够完整恢复到目标时间点。