必须先压缩revision、再defrag、最后disarm alarm,三步缺一不可;否则即使磁盘空间已释放,etcd仍拒绝写入,集群持续失联。

etcd 空间写满后集群失联,不是磁盘满了就删文件,而是必须先压缩 revision、再 defrag、最后 disarm alarm,三步缺一不可;否则即使 df 显示空间已释放,etcd 仍拒绝写入。
确认是否真因 mvcc: database space exceeded 失联
看到 kubectl get node 超时、etcdctl endpoint health 返回 unhealthy 或直接报错,先别急着重启。重点查日志和指标:
- 在任一 etcd 节点执行
journalctl -u etcd -n 50 --no-pager | grep -i "space\|exceeded",若出现mvcc: database space exceeded,就是它了 - 运行
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 alarm list,输出含alarm: NOSPACE即确认触发配额告警 - 用
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 endpoint status --write-out=table查DBSize,若接近或等于quota-backend-bytes(默认 2GB 或 8GB),基本坐实
执行安全清理:compact → defrag → alarm disarm
顺序绝对不能错,且必须在同一个节点上连续执行(推荐 Leader 节点):
- 先获取当前 revision:
rev=$(ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 endpoint status --write-out=json | grep -o '"revision":[0-9]*' | grep -o '[0-9]*') - 执行压缩(只保留 ≥ $rev 的版本):
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 compact $rev;注意:这不会丢当前数据,但会清掉旧历史版本 - 立即碎片整理(真正释放磁盘空间):
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 defrag;该命令阻塞 etcd 服务数秒至数十秒,期间读请求仍可响应,写请求排队 - 最后解除告警:
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 alarm disarm;跳过这步,etcd 永远拒绝写入
针对性清理高增长路径(如 /registry/events/)
K3s 或长期运行的集群中,/registry/events/ 和 /registry/minions/ 常因事件风暴或心跳堆积大量 key,占空间却不影响核心功能:
- 统计事件数量:
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 get --prefix /registry/events/ | wc -l,超 5000 条就值得清理 - 安全删除:
ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 del --prefix /registry/events/;Kubernetes controller 会按需重建必要事件 - 严禁对
/registry/pods/、/registry/nodes/、/registry/secrets/等路径使用--prefix删除——这等于直接抹掉集群状态
预防复发:必须配置自动压缩与扩容
人工清理只是救火,不设自动机制,一个月内大概率复现:
- 修改 etcd 启动参数,加入:
--auto-compaction-mode=revision --auto-compaction-retention=1000 --quota-backend-bytes=8589934592(即 8GB) - 其中
--auto-compaction-retention=1000表示每 5 分钟自动压缩,只保留最近 1000 个 revision;太小(如 100)会导致 watch 历史过短,controller 可能漏事件 - 切勿只调大
quota-backend-bytes而不配自动压缩——空间迟早还会爆,只是晚几天而已
最容易被忽略的是:清理完后没跑 alarm disarm,或者把 compact 和 defrag 顺序搞反。前者让集群持续只读,后者导致 defrag 无效——磁盘空间根本没真正释放。











