3. 数据压缩(Compaction)原理:删除旧版本,回收空间

etcd 是一个多版本并发控制(MVCC)的键值存储。每次对键的 put 或 delete 操作,etcd 不会原地覆盖数据,而是生成一个新的版本记录。随着时间推移,历史版本会不断累积,导致存储空间膨胀、读写性能下降。数据压缩(Compaction)正是解决这一问题的核心机制——它通过删除指定版本之前的所有旧数据,回收磁盘空间,同时保持最新数据的可访问性。

3.1 MVCC 与版本堆积

在 etcd 中,每个键值对都关联一个全局递增的 revision(修订版本号)。当执行写操作时,etcd 会追加一条新的记录,而旧记录仍然保留在存储引擎(BoltDB)中。下图展示了 MVCC 下的版本链结构:

etcd MVCC 版本链与压缩范围 MVCC 版本链与压缩范围示意 rev=1 rev=2 rev=3 rev=4 rev=5 rev=6 rev=7 压缩范围:删除 rev ≤ 4 的所有历史版本 保留区域:rev > 4 的版本 说明: • 蓝色节点:普通写入版本;红色节点:删除标记(tombstone);绿色节点:当前最新版本 • 压缩后,rev=1~4 的数据从 BoltDB 中删除,但 rev=5~7 仍可正常读写
关键理解:压缩不是删除“最新数据”,而是删除“过时的历史版本”。即使执行了 delete 操作,etcd 也只是写入一个删除标记(tombstone),真正的数据清理依赖压缩机制。

3.2 压缩的两种模式

etcd 支持两种压缩模式,分别适用于不同的运维场景:

模式 触发方式 压缩依据 典型场景
时间模式(Time-based) 自动(周期性) 保留最近 N 小时内的所有版本 生产环境默认推荐,避免手动干预
版本模式(Revision-based) 手动或 API 调用 保留从指定 revision 开始到最新的版本 故障恢复、数据迁移、精确控制

3.2.1 时间模式(自动压缩)

通过启动参数 --auto-compaction-retention 设置保留时长,单位可以是小时(h)或分钟(m)。etcd 会周期性地计算当前时间与保留时长的差值,然后压缩掉所有早于该时间点的版本。

# 保留最近 1 小时的数据,自动压缩更早的版本
etcd --auto-compaction-retention=1h

# 保留最近 30 分钟
etcd --auto-compaction-retention=30m

3.2.2 版本模式(手动压缩)

通过 etcdctl 或 gRPC API 指定一个 revision 号,etcd 会删除所有小于等于该 revision 的历史数据。此模式需要运维人员对数据版本有清晰认知。

# 压缩所有 revision <= 1000 的数据
etcdctl compaction 1000

# 查看当前最新的 revision
etcdctl endpoint status --write-out=table
⚠️ 风险提示:版本模式压缩不可逆。如果指定的 revision 过大(例如压缩到当前最新 revision),可能导致 etcd 丢失所有历史数据,甚至影响 watch 和线性化读操作。生产环境建议优先使用时间模式。

3.3 压缩的内部流程

当触发压缩时,etcd 会执行以下步骤:

  1. 计算压缩目标 revision:根据时间或用户指定的 revision,确定一个截止 revision compactRev。
  2. 标记 BoltDB 中的过期数据:遍历 BoltDB 的 bucket,标记所有 revision ≤ compactRev 的键值对为“可删除”。
  3. 删除历史版本记录:从 BoltDB 中物理删除这些标记的数据条目,释放 B+ 树中的页面空间。
  4. 更新元数据:在 etcd 的元数据 bucket 中记录本次压缩的 revision,供后续操作(如 watch)参考。
  5. 触发碎片整理(可选):压缩仅删除数据,但 BoltDB 文件大小不会立即缩小。需要后续执行 defrag 才能回收磁盘空间(详见下一章)。
etcd 压缩内部流程 etcd 压缩内部执行流程 1. 触发压缩 2. 计算 compactRev 3. 标记过期数据 4. 物理删除数据 流程说明: • 触发方式:自动(时间)或手动(版本) • compactRev 是压缩截止版本号 • 标记阶段不立即删除,避免阻塞 • 删除后 BoltDB 文件大小不变 • 需配合 defrag 回收磁盘空间 输出:压缩后的逻辑空间释放

3.4 压缩对存储的影响

压缩完成后,etcd 的存储空间变化如下:

指标 压缩前 压缩后 说明
逻辑数据量 高(包含所有历史版本) 低(仅保留最新版本) 查询和 watch 效率提升
BoltDB 文件大小 大 不变(或略微减小) 物理空间未回收,内部出现空闲页面
磁盘碎片 较少 增多 空闲页面分散,需要 defrag 整理
读写性能 可能下降(B+ 树膨胀) 提升(B+ 树高度降低) 索引扫描更快
核心结论:压缩是 etcd 存储管理的“第一步”,它释放了逻辑空间,但物理空间回收需要依赖后续的碎片整理(defrag)。两者配合使用,才能实现存储空间的真正优化。

3.5 压缩的最佳实践

  • 生产环境始终开启自动压缩:推荐保留时长 1h 或 2h,根据业务对历史版本的需求调整。
  • 避免过于频繁的压缩:压缩本身消耗 I/O 和 CPU,过于频繁(如每几分钟一次)可能影响集群性能。
  • 监控压缩状态:通过 etcdctl endpoint status 查看 DB SIZE 和 COMPACT REVISION,确认压缩是否正常执行。
  • 压缩后及时执行 defrag:在业务低峰期执行碎片整理,回收磁盘空间。
  • 版本模式谨慎使用:仅在故障恢复或数据迁移等特殊场景下手动压缩,并确保指定合理的 revision。