必须先执行compact标记旧版本,再defrag回收物理空间,最后alarm disarm解除写入限制;三步缺一不可,且需在每个etcd节点依次执行,否则仍拒绝写入。

在线对 etcd 集群执行无损碎片整理(defrag)是释放磁盘空间、提升性能的关键操作,但必须配合压缩(compact)并严格按顺序进行——defrag 本身不删数据,只回收被 compact 标记的空闲页;单独 defrag 无效,且会短暂阻塞读写。
确认当前状态与触发条件
碎片整理前需验证是否真因空间满导致异常(如 mvcc: database space exceeded):
- 运行
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 endpoint status --write-out=table,检查 DBSize 是否接近默认配额(2GB),以及 IsLeader 和告警字段 - 若输出含
alarm:NOSPACE,说明已触发空间告警,此时写入已被拒绝,必须先 compact + defrag + disarm 才能恢复 - 注意:仅 DBSize 大 ≠ 必须 defrag;只有 compact 后未 defrag,或长期未维护导致 boltdb 文件膨胀严重时,defrag 才真正释放物理空间
获取最新 revision 并执行压缩
defrag 的前提是有可回收的历史版本,这依赖 compact 操作标记旧数据:
- 提取当前最大 revision:
rev=$(ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 endpoint status --write-out=json | jq -r '.[0].Status.header.revision') - 执行压缩(逻辑清理):
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 compact $rev
该命令保留所有 ≥ $rev 的键值版本,Kubernetes 当前对象状态完全不受影响 - 若集群启用了 TLS(如 K3s 或标准 k8s),需补全证书参数:
--cacert=/path/ca.crt --cert=/path/server.crt --key=/path/server.key
执行 defrag 并解除告警
compact 完成后立即 defrag,才能把标记为空闲的磁盘页真正回收:
- 运行 defrag:
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 defrag
执行期间该节点会短暂阻塞(通常 1–3 秒),但不影响其他节点服务,Raft 自动处理请求重定向 - 查看效果:再次运行
endpoint status,DBSize 应明显下降(例如从 1.8G → 220M) - 必须解除告警:
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 alarm disarm
否则即使空间已释放,etcd 仍拒绝写入 - 多节点集群中,需在每个 etcd 成员上**依次执行以上三步**(compact → defrag → disarm),避免跨节点状态不一致
预防复发:配置自动压缩与定期维护
靠手动清理治标不治本,建议从机制上减少碎片积累:
- 启动 etcd 时添加参数:
--auto-compaction-retention=1h,自动每小时 compact 一次,保留最近 1 小时历史 - 注意:自动 compaction 不等于自动 defrag,仍需定期脚本触发 defrag(例如每天低峰期 cron 执行)
- 生产环境推荐组合策略:
• 每小时 auto-compaction
• 每日凌晨执行 compact + defrag + disarm 脚本
• 每周备份快照并清理过期备份(防止 backup 占满磁盘)











