cgroup内存泄漏会导致系统硬崩溃;可通过检查/proc/cgroups中num_cgroups值、对比/sys/fs/cgroup/memory下目录数与实际容器数、perf top观察cache_reap热点来确认;紧急时手动清空cgroup.procs并删除空子树;根治需升级cgroups v2、禁用kmem accounting、配置docker自动清理;长期须监控cgroup数量并设告警。

多服务长周期运行后,cgroup 资源节点残留(尤其是 memory cgroup)会引发硬崩溃——不是报错退出,而是系统卡死、load 飙升、kworker 占满 CPU、甚至整机无响应。这不是应用层问题,而是内核资源管理机制被拖垮的典型表现。
确认是否为 cgroup 泄漏导致的硬崩溃
先验证问题本质,避免误判为硬件或网络故障:
- 执行
cat /proc/cgroups | grep memory,若num_cgroups值超过 10 万(尤其达 20w+),基本可判定泄漏严重 - 运行
ls /sys/fs/cgroup/memory/ | wc -l,对比容器实际数量(docker ps -a | wc -l或kubectl get pods --all-namespaces | wc -l),若前者远大于后者,说明大量已退出容器的 cgroup 未清理 - 用
perf top观察热点函数,若cache_reap持续高占比,且伴随 slab_caches 链表遍历耗时激增,即为内存 cgroup 泄漏触发的内核路径恶化
紧急止血:手动清理残留 cgroup(适用于已卡顿但未完全失联)
该操作需 root 权限,不重启 dockerd 或 kubelet 即可释放压力:
- 逐个清空孤立 memory cgroup 的进程列表:
for d in /sys/fs/cgroup/memory/docker-*; do echo 0 > $d/cgroup.procs 2>/dev/null; done - 强制卸载无引用的 cgroup 子树(仅限 cgroup v1):
find /sys/fs/cgroup/memory -maxdepth 2 -name "docker-*" -empty -delete 2>/dev/null || true - 同步清理 kmem accounting(若启用):
echo 0 > /sys/fs/cgroup/memory/docker-*/memory.kmem.limit_in_bytes 2>/dev/null
根治方案:从运行时与内核双侧阻断泄漏
单纯清理是治标,必须切断泄漏源头:
-
升级并启用 cgroups v2:v2 统一了资源控制器,消除了 v1 中 memory + kmem 分离导致的计数器分裂问题;Docker 24.0+、K8s 1.26+ 默认支持,需在 grub 中添加
systemd.unified_cgroup_hierarchy=1 -
禁用 kmem accounting(临时兜底):在内核启动参数中加入
cgroup.memory=nokmem,可规避 slabinfo 链表膨胀,但会失去内核内存精确追踪能力 -
配置 dockerd 的自动清理策略:在
/etc/docker/daemon.json中添加:"live-restore": true, "default-ulimits": { "memlock": { "Name": "memlock", "Hard": -1, "Soft": -1 } },并确保dockerd启动时带--cgroup-parent=system.slice防止子 cgroup 逃逸到根路径
长期防护:监控与告警必须覆盖 cgroup 健康度
把 cgroup 数量纳入 SLO 指标,而非只盯 CPU 和内存:
- 用 Prometheus + node_exporter 抓取
node_cgroup_subsystems{subsystem="memory"}和node_cgroup_num_cgroups{subsystem="memory"} - 设置告警规则:当
node_cgroup_num_cgroups{subsystem="memory"} > 5000并持续 5 分钟,立即触发人工介入或自动执行清理脚本 - 每日巡检脚本中加入:
if [ $(cat /proc/cgroups | awk '/memory/{print $4}') -gt 10000 ]; then echo "ALERT: memory cgroup count too high"; fi


















