etcd 为什么越用越大?删了数据文件却不变小?compact 和 defrag 各做什么?这篇往 etcd 里写入 100KB 的 key,覆盖三遍,再依次 compact、defrag,把 dbSize 和 dbSizeInUse 的变化逐步量出来。
写 200 个 100KB 的 key(17 秒):dbSize=21.0 MiB(+20.3 MiB);dbSizeInUse=20.3 MiB;revision 144664 → 144893(+229:200 次写,其余是集群自己的写入)
基线(清空测试 key、compact、defrag 之后)dbSize=0.8 MiB。往 etcd 写 200 个 100KB 的 key(17 秒):dbSize 涨到 21.0 MiB(+20.3 MiB),revision 从 144664 到 144893(+229,其中 200 次是我们的写,其余是集群自己的写入)。kube-apiserver 记下的最近压缩位置 compact_rev_key 是 142537,落后于当前 revision 一小段。
覆盖写 3 遍后:dbSize=79.2 MiB(+58.2 MiB);dbSizeInUse=77.7 MiB;revision 144893 → 145573(+680,600 次写加集群自己的写入)——实际有效数据只有 200 个 key 约 19.1 MiB,其余都是旧版本 用 --rev=144694(第一遍写入时)读 /k91/0000:还能读到,长度 100000 字节(旧版本还在)
把同一批 key 覆盖写 3 遍:dbSize 79.2 MiB,dbSizeInUse 77.7 MiB,revision 到 145573,而有效数据其实只有约 19.1 MiB——其余都是旧版本。用 --rev 读第一遍写入时的 /k91/0000 还能读到 100000 字节:旧版本都在,这是 watch 与一致性读的基础,也是空间的来源。Lease、Event、Node status 这类频繁更新的对象最容易吃空间。
etcdctl compact 145573:compacted revision 145573 再读 --rev=144694:required revision has been compacted compact 之后:dbSize=79.5 MiB(几乎没变);dbSizeInUse=20.0 MiB(降了 57.7 MiB)——文件里出现了大量可复用的空闲页,但文件本身不缩
etcdctl compact 145573 之后,再读旧 revision 得到 required revision has been compacted。dbSizeInUse 从 77.7 降到 20.0 MiB,但 dbSize 仍是 79.5 MiB——旧版本占的页被标记为空闲、可以复用,可是 bbolt 文件本身不会缩小。监控磁盘空间时要看 dbSizeInUse 与 dbSize 的差。kube-apiserver 默认每 5 分钟做一次压缩,etcd 自己没有开自动压缩。
etcdctl defrag(0.3 秒):Finished defragmenting etcd member[https://127.0.0.1:2379]. took 228.738125ms;dbSize=79.5 MiB → 20.0 MiB;dbSizeInUse=20.0 MiB(现在两者接近) 把测试 key 删掉后再 compact + defrag:dbSize=0.8 MiB(回到基线 0.8 MiB 附近);revision=145580 etcd 的启动参数里 quota-backend-bytes / auto-compaction:都没有设置,用默认值(db 配额默认 2 GiB;etcd 自己不自动压缩,由 kube-apiserver 每 5 分钟压缩)
etcdctl defrag(0.3 秒;大库会久得多,期间该成员的读写会被阻塞)之后 dbSize 从 79.5 缩到 20.0 MiB,和 dbSizeInUse 一致。把测试 key 删掉再 compact + defrag,dbSize 回到 0.8 MiB。etcd 启动参数里没设 quota-backend-bytes(默认配额 2 GiB),超过配额会进入告警、只读状态,所以磁盘空间要靠定期 compact 与 defrag 来管理。