Linux cgroup v2 memory.oom.group 怎样统一处理进程组内存不足
来源:17golang原创
时间:2026-10-20 02:20:28 260浏览 收藏
多进程服务被 cgroup v2 限制后,最难排查的情况不是“进程被杀”,而是只剩下一半:主进程还在,工作进程已经退出;或者 sidecar 仍然存活,但它依赖的服务状态已经不完整。需要整体处理这类工作负载时,可以在目标非根 cgroup 中设置 memory.oom.group=1。
这个开关的含义是:当 OOM killer 在该 cgroup 内做决定时,把该 cgroup 及其后代中的任务视为不可拆分的工作负载,整体杀掉或整体不杀。它不会替代 memory.max,也不会把系统中其他 cgroup 的进程一起清理。
官方文档:https://docs.kernel.org/admin-guide/cgroup-v2.html
影响面:为什么只退出一个进程会留下残缺服务
假设一个服务由 master、worker 和 sidecar 组成,三者共享同一个 cgroup。内存达到上限后,回收无法继续,内核进入该 cgroup 的 OOM 处置路径。如果仍使用默认的 memory.oom.group=0,可能出现单个任务退出而其他任务继续运行的状态。
这种状态会把故障伪装成“服务还活着”:健康检查可能只看到 master,队列却没人消费;sidecar 还能上报心跳,却无法代表业务完成。复盘时先看工作负载是否允许部分存活,再决定是否需要组级处置。
触发条件:memory.max 负责上限,OOM 决策负责处置
memory.max 是硬内存边界。达到边界后,内核会先尝试直接回收;回收不能把使用量降下来时,分配可能进入 OOM 状态。memory.oom.group 只影响 OOM killer 如何选择该 cgroup 内的任务,不会让上限变大,也不会阻止前面的回收。

可以把排查问题拆成三层:先确认目标 cgroup 确实启用了 memory 控制器,再确认内存上限是否在目标层级生效,最后确认被管理的进程是否都属于同一工作负载。不要把“进程退出”直接等同于“组策略生效”。
修复动作:把相关任务放入同一 cgroup 再开启组级策略
下面的命令是配置示例。路径和 PID 需要替换成实际环境中的值;示例只展示接口关系,不代表已经在本机执行。
# 目标 cgroup 由父级下放 memory 控制器后再使用 CG=/sys/fs/cgroup/my-service sudo mkdir -p "$CG" # 将同一工作负载视为不可拆分的 OOM 处置单元 echo 1 | sudo tee "$CG/memory.oom.group" # 把 master 放入目标 cgroup;它创建的子进程通常继承该归属 echo "$MAIN_PID" | sudo tee "$CG/cgroup.procs" # 读取策略值,确认配置文件里的当前设置 cat "$CG/memory.oom.group"
如果由 systemd、容器运行时或其他管理器创建 cgroup,应把这项配置放在管理器的资源配置层,而不是发布后手工写一次。手工写入可能在服务重启、单元重新生成或容器重建时丢失。

边界判断:哪些任务不会按组级策略被杀
第一,memory.oom.group 只影响触发 OOM 的那个 cgroup 及其后代,不会因为祖先 cgroup 设置了组策略,就把目标 cgroup 外的任务纳入处置。第二,设置了 oom_score_adj=-1000 的任务属于例外,内核文档明确说明这类任务不会被该 OOM 处置杀掉。
第三,进程迁移后,资源归属和进程归属不一定同时变化;服务启动时就应把 master、worker 等逻辑上不可拆分的成员放入正确层级。第四,组级杀进程不等于自动恢复,仍要由 systemd、容器编排器或服务自身的 supervisor 负责重新启动和清理。
防复发:发布后保留三项排查证据
每次调整内存策略后,至少保留三类信息:目标 cgroup 的路径和 memory.oom.group 当前值;关键 PID 的 /proc/PID/cgroup 归属;服务管理器记录的退出与重启原因。这样才能区分“配置没有加载”“进程没有进入目标组”和“组策略生效但服务没有恢复”三种情况。
| 排查对象 | 要回答的问题 | 不要误判成 |
|---|---|---|
memory.max | 目标组的硬上限是什么 | 组级 OOM 开关 |
memory.oom.group | OOM 时是否整体处置 | 提高可用内存 |
cgroup.procs 与 /proc/PID/cgroup | 哪些任务实际属于工作负载 | 只看服务名猜归属 |
总结一下:先确认服务是否允许部分存活,再在同一 cgroup 内配置 memory.oom.group=1;同时保留 OOM 保护任务、祖先边界和进程归属这三个例外判断。这个方案解决的是“如何整体处置”,不是“如何避免触发内存上限”。
相关问题
设置 memory.oom.group=1 会扩大 memory.max 吗?
不会。它只改变 OOM killer 在目标组内的处置粒度,内存上限仍由 memory controller 的其他接口决定。
为什么 sidecar 还活着但业务已经不可用?
可能是 sidecar 与 worker 不在同一个目标 cgroup,或者仍使用默认的单任务处置策略。应先核对每个 PID 的 cgroup 归属,再判断是否需要把工作负载作为整体管理。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
221 收藏
-
218 收藏
-
478 收藏
-
387 收藏
-
500 收藏
-
171 收藏
-
230 收藏
-
256 收藏
-
496 收藏
-
142 收藏
-
243 收藏
-
423 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习