土法炼钢 · 系统与基础设施

【etcd】Compaction、Defrag 与容量:quota、alarm 与 SLO

文章导航

分类入口
distributedkubernetes
标签入口
#etcd#compaction#defrag#quota#alarm#mvcc#bbolt#v3.5.33

目录

第 9 篇 说明 CompactRevision → ErrCompacted第 7 篇 提过 quota 门。运维里常见混淆是 compaction 与 defrag 当一件事,或 quota 触顶先 defrag——实际上:compaction 删历史 revision;defrag 回收 bbolt 文件空洞;quota 看 Backend().Size() 与 alarm 写禁。

本篇钉 v3.5.33 容量轴三件套:Compact/scheduleCompactionv3compactor auto-compaction、Defrag 在线重组,以及 DefaultQuotaBytes = 2GiBNOSPACE alarm。不写未测磁盘曲线。

本篇在系列中的位置

篇目 核心内容
第 11 篇 · Txn 与并发语义 compare/mod、Jepsen 边界
第 12 篇 · Compaction、Defrag 与容量 compaction、defrag、quota、SLO
第 13 篇 · Kubernetes 控制面耦合 resourceVersion、Node Lease
系列目录 五轴、阅读路径

版本锚定:etcd v3.5.33(tag v3.5.33)。对齐 server/mvcc/kvstore_compaction.goserver/mvcc/backend/backend.goDefrag)、server/etcdserver/quota.goserver/etcdserver/api/v3compactor/ @ etcd-io/etcd v3.5.33。默认 --quota-backend-bytes=0 表示启用 2GB quota(非「无限制」)。无真实集群则不粘贴伪造 endpoint status dbSize 数字。


一、Compaction:裁 revision,不缩文件

Manual compactCompact(rev) 经 Raft propose → store.compactscheduleCompaction

  1. treeIndex.Compact(rev) 更新内存索引,返回需保留的 revision 集合 keep
  2. 分批 UnsafeRange + UnsafeDelete 清理 buckets.Key< rev 且不在 keep 的条目;
  3. 写入 finishedCompactKeyNamecompactMainRev = rev

Compaction 降低 MVCC 历史深度,使 Watch 从旧 startRev 追赶时可能命中 minRev < compactMainRev(第 9 篇)。Range 指定 Rev < compactMainRev 返回 ErrCompacted

未完成 compaction 恢复scheduledCompactKeyNameRestore 路径可在重启后继续(kvstore.go)——排障「长时间 compacting」应查 scheduled vs finished meta key,而不是直接 defrag。

flowchart LR
  compact["Compact(rev)"] --> index["treeIndex.Compact"]
  index --> bolt["bbolt 删旧 revision KV"]
  bolt --> meta["finishedCompact rev"]
  meta --> watch["unsynced: CompactRevision"]
  meta --> range["Range@oldRev: ErrCompacted"]

二、Auto-compaction:保留窗口 vs 恢复能力

EtcdServerAutoCompactionRetention != 0 时构造 v3compactorperiodic.go / revision.go):

Leader 失去 leadership 时 compactor.Pause(),重新 Leader 时 Resume()server.go updateLeadership)——避免 Follower 上错误触发 compact。

SLO 写法(工程判断,非官方 SLA)

指标 依赖 风险
Watch 可续传窗口 ≥ 客户端最大断线时间 + apiserver resync 保留过短 → ErrCompacted 风暴
磁盘增长 写入率 × 保留 revision 宽度 只 compact 不 defrag → SizeInUse ≪ Size
恢复 / 备份 最近 compact rev 之后仍可做增量语义 过 aggressive compact 丢 historical read

K8s 官方文档建议控制 db size 与 defrag 窗口(B 级运维指南);本篇不复制未核实的 GB 阈值表。


三、Defrag:缩 bbolt 文件,不替 compaction

backend.Defrag()backend.go):

Defrag 不删除 MVCC 历史——只把 compaction 后的空洞从文件物理移除。日志字段 current-db-size vs current-db-size-in-use 差值大时,defrag 才有明显效果。

Prometheus etcd_mvcc_db_total_size_in_use_bytes / etcd_mvcc_db_total_size_bytesisDefragActive gauge 可用于变更窗口观测;本篇无实测 shrink 比例

运维口令:先 compact 到目标 rev → 低峰 defrag 单 member(避免全集群同时锁 store);与 snapshot 备份窗口错开(第 14 篇)。


四、Quota 与 NOSPACE alarm

DefaultQuotaBytes = 2 * 1024 * 1024 * 10242GiB);MaxQuotaBytes = 8GiB(超过仅 warn,仍允许配置)。

backendQuota.AvailableBackend().Size() + Cost(req) < maxBackendBytes。Cost 估算:

Apply 返回 ErrNoSpace 时(server.go applyEntryNormal):

  1. 若尚无 NOSPACE alarm → 异步 Alarm ACTIVATE NOSPACE
  2. applierV3Capped 拒绝后续 mutating(只读仍可部分进行——见 apply.go alarm 分支)。

Disarm:compact + defrag 降 Size()etcdctl alarm disarm(需理解 10% mmap 余量:QuotaBackendBytes + QuotaBackendBytes/10 用于 MmapSizebackend.go)。

现象 首要动作
database space exceeded MVCC/quota compact → defrag → 升 quota(≤8G 慎)
写拒绝、alarm NOSPACE alarm disarm 前必须 真正腾出 Size
读 old rev 失败 compaction 客户端全量 sync,非 defrag
dbSize 大、in-use 小 空洞 defrag

CORRUPT alarm 切换 applierV3Corrupt(只读防护)——与容量轴不同,见 corrupt checker(第 15 篇)。


五、与 Watch / K8s 的 SLO 耦合

  1. auto-compaction-retention 过短:controller/apiserver Watch 从旧 resourceVersion 续传失败 → 与 第 9 篇 ErrCompacted 同一机制;
  2. quota 触顶:写 Node Lease、Status 失败 → 表象像 Lease/TTL 轴(第 10 篇),根因常在 MVCC 轴
  3. defrag 停顿:短窗口内 ReadIndex/apply 延迟上升——与 Raft lag 分列(apply 等锁,非复制慢)。

建议 SLO 文档显式写三项:compaction 保留 ≥ 最大 watch 落后时间quota 告警在 80% Sizedefrag 变更单 per member。数字阈值须来自 本集群 metrics + 变更记录,非本文臆测。


六、谱系与开放问题

MVCC 时间旅行(多版本)→ 历史必须裁剪(compaction)
  → bbolt 追加写 → 空洞 → defrag
  → 单 store quota → Multi-Raft 扩展性天花板(TiKV 对照)
  → 开放:K8s 大规模下 auto-compaction 与 apiserver bookmark 的联合调参无公开形式模型

开放问题:2GiB 默认 quota 对 modern 控制面是否偏小属于 workload 依赖;迁 TiKV/FDB 的否证条件见 distributed/39 与第 16 篇——不在本篇给 QPS 排行

本篇不写什么:未跑的 defrag 耗时 benchmark;etcdctl check perf 伪造输出;TiKV/FDB 内核重讲。


参考资料

规范 / 官方文档 / 源码(A)

运维指南(B)

站内对照


上一篇Txn 与并发语义

下一篇Kubernetes 控制面耦合

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .