已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
背景
我在一个 3 节点自建 K8s(1.28.9 + containerd 1.6.24,节点 16C64G,内核 5.15.0-91,cgroup v2)里把 etcd 拆到独立节点单独管,数据目录在本地 NVMe。业务侧 revision 增长很快(ConfigMap/Secret/Lease 轮转 + 一个 CRD reconcile 频繁写 status,etcd_server_proposed_duration_seconds 看着正常,但 db_total_size 从 1.2G 两周涨到 9.8G)。
现象
etcdctl compact + 周期性跑),历史 revision 能跟上,db_total_size 的"虚胖"确实压下来了——但 db_size_in_use 和 db_total_size 之间长期差 2~3G,说明被删的 revision 标记了没回收,物理空间不释放,这块我知道就是缺 defrag。ETCDCTL_API=3 etcdctl defrag --cluster 那一下,etcd 进程 RSS 瞬时从稳态 ~1.1G 冲到 4.7G(我后来用 etcd_server_follower_promote_duration_seconds 之外的 process_resident_memory_bytes 抓到的),节点当时还压着一个 6G 的日志采集器,直接触发了 kubelet 内存驱逐 + etcd 容器被 OOM,一次 defrag 把本来该收敛的库搞成了要 snapshot 恢复的事故。已尝试的排查与结果
--cluster,逐节点串行)——内存尖峰从 4.7G 降到 ~2.8G,比之前好,但在 64G 节点压了别的服务时仍然危险,而且逐节点串行让集群 defrag 窗口拉长了。memory.max)——加了之后 OOM 还是发生,但这次是 etcd 自己先被 cgroup OOM kill,更糟(节点至少还活着,现在连库都翻了)。etcd_mvcc_db_total_size_in_bytes 与 in_use 的差值,确认确实有 ~2.5G 可回收,但没找到"defrag 瞬时内存 = f(可回收量, 当前水位)"的量化经验。期望得到的答案形态 希望做过同类 defrag 的朋友给可复现的做法,最好包含:
memory.current / PSI 给一个硬阈值(比如"节点可用内存 < X 就不许 defrag")?memory.max 到底该设成防不住还是该设成兜底?有没有人在 defrag 前临时把同节点的重服务(采集器之类)驱逐走再跑?--cluster:在 3 节点里,哪种 defrag 顺序对内存尖峰最友好?Leader 先 defrag 还是 follower 先?我会把最终落地的 SOP 沉淀成经验文章,欢迎贴你们线上的真实数字。