cgroup v2 限制服务内存并观察回收事件
服务内存异常时,先别急着把机器的总内存调大。cgroup v2 更适合把“这一个服务最多能用多少”和“达到压力后如何回收”拆成两层:用 memory.high 施加回收压力,用 memory.max 设置硬边界,再用 memory.current、memory.events 和 memory.events.local 判断究竟发生了什么。
memory.high是压力阈值,超过后会触发更重的回收和节流,不等同于立即 OOM。memory.max是硬上限,无法回收时可能在该 cgroup 内触发 OOM。memory.events默认包含层级统计,定位当前服务时还要对照memory.events.local。
一、先确认主机真的使用 cgroup v2
先查看挂载点和可用控制器。以下命令只读系统状态,示例路径假定统一层级挂在 /sys/fs/cgroup。
# 确认目标目录是否为 cgroup2 文件系统 stat -fc %T /sys/fs/cgroup # 查看当前层级可以向子 cgroup 提供哪些控制器 cat /sys/fs/cgroup/cgroup.controllers # 查看根层级已经向子 cgroup 开启了哪些控制器 cat /sys/fs/cgroup/cgroup.subtree_control
第一条命令应看到 cgroup2fs。如果 cgroup.controllers 中没有 memory,先检查内核配置、挂载方式和上级层级,而不是直接向目标目录写入 memory.max。v2 的控制器需要由父层级通过 cgroup.subtree_control 提供给子层级。

二、为服务建立 memory.high 和 memory.max 边界
确认控制器可用后,创建一个只用于示例服务的叶子 cgroup。这里把可回收压力阈值设为 512 MiB,把硬上限设为 768 MiB;实际数值应根据服务稳定工作集、缓存策略和突发流量压测结果确定。
# 创建服务专用的 cgroup 目录 sudo mkdir -p /sys/fs/cgroup/demo-api # 超过该值后增加回收压力和节流,但不直接等同于 OOM echo 512M | sudo tee /sys/fs/cgroup/demo-api/memory.high # 无法继续回收时的硬边界;max 表示不设硬上限 echo 768M | sudo tee /sys/fs/cgroup/demo-api/memory.max # 读取内核实际接受的值,避免只相信写入命令没有报错 cat /sys/fs/cgroup/demo-api/memory.high cat /sys/fs/cgroup/demo-api/memory.max
memory.high 适合做服务保护的第一道边界:它让超出阈值的工作负载承受更强回收压力。memory.max 才是硬限制,但内核文档也明确指出,某些情况下使用量可能暂时超过它,且部分分配路径不会按普通 OOM 方式处理。因此这两个值不能简单理解成“512 MiB 和 768 MiB 两个精确瞬时开关”。
三、让服务进程真正归属这个 cgroup
只创建目录并不会改变服务归属。对已经启动的单进程服务,可以把 PID 写入 cgroup.procs;systemd 管理的服务则更适合把限制写到 unit,让重启后仍然有效。
# 读取目标服务的 PID;这里的服务名仅作示例 pid="$(systemctl show -p MainPID --value demo-api.service)" # 把主进程加入目标 cgroup,生产环境还要确认子进程继承和权限边界 echo "$pid" | sudo tee /sys/fs/cgroup/demo-api/cgroup.procs # 核对 PID 当前是否已经出现在目标 cgroup grep -w "$pid" /sys/fs/cgroup/demo-api/cgroup.procs
如果服务由 systemd 托管,持久配置可以使用资源控制属性:
# 为 unit 写入可持久化的内存压力阈值和硬上限 sudo systemctl set-property demo-api.service MemoryHigh=512M MemoryMax=768M # 查看 systemd 展开的属性,确认 unit 层配置已生效 systemctl show demo-api.service -p MemoryHigh -p MemoryMax
手工写 cgroup 文件适合排查和一次性实验;长期运行的服务应让 systemd 或其他编排层成为唯一配置来源,避免重启、迁移和子进程管理把限制丢掉。
四、用 current 和 events 判断发生了哪类压力
先看当前使用量,再看事件计数。计数变化说明边界曾被触碰,但不能单独证明某一次请求就是唯一原因。
# 当前 cgroup 的内存使用量,单位为字节 cat /sys/fs/cgroup/demo-api/memory.current # 读取包含子层级的事件统计 cat /sys/fs/cgroup/demo-api/memory.events # 只读取 demo-api 自身产生的事件,便于排除子 cgroup 干扰 cat /sys/fs/cgroup/demo-api/memory.events.local
常见字段可以这样理解:
| 字段 | 它说明什么 | 排查重点 |
|---|---|---|
high | 内存使用触碰过 high 边界 | 工作集是否长期高于阈值,是否出现持续节流 |
max | 使用量触碰过 max 边界 | 回收是否跟不上,是否需要拆分缓存或降低并发 |
oom | cgroup 内发生过 OOM 触发 | 结合服务日志和进程退出时间判断影响面 |
oom_kill | 发生过 OOM kill | 优先保留计数与日志,不要只看一次 current |

五、按照现象调整,而不是看到 max 就盲目放大
如果 high 持续增长而 oom_kill 不变,通常先检查工作集、缓存上限和并发,再评估是否提高 memory.high。如果 max、oom 或 oom_kill 增长,要把它当作硬边界告警,核对服务是否被杀、是否有子 cgroup 分摊,以及 memory.events 的层级统计是否把后代事件算进来了。
复查时至少保留三份信息:限制值(memory.high、memory.max)、当前值(memory.current)和事件快照(memory.events.local)。如果需要主动回收,memory.reclaim 可以触发目标 cgroup 的回收,但它是管理接口,不能用来伪造“发生了内存压力”的业务证据;回收结果也可能多于或少于请求值。
常见问题
memory.high 达到后会马上杀掉服务吗?
不会。它主要引入更重的回收和节流;真正的硬边界是 memory.max,也仍应结合事件和服务日志判断结果。
为什么 memory.events 和 memory.events.local 数字不一样?
memory.events 默认是层级统计,可能包含后代 cgroup;memory.events.local 只看当前 cgroup。服务拆分子组时应同时读取两者。
systemd 和手工写 memory.max 选哪个?
一次性定位问题可以手工写文件;长期服务优先使用 systemd 的 MemoryHigh、MemoryMax,让限制和 unit 生命周期一起管理。
最后用一张清单复查:控制器是否已向子层级开放、服务 PID 是否在目标 cgroup、high/max 是否符合工作集、events 是否按 local 与 hierarchy 分开解释。这样看到“回收事件增加”时,才能知道是在保护服务,还是已经撞上了硬边界。
繁花动漫怎么选画质?高清、超高清与4K阅读说明
- 上一篇
- 繁花动漫怎么选画质?高清、超高清与4K阅读说明
- 下一篇
- Go 文件权限 umask 与 Chmod 结果的关系
-
- 文章 · linux | 1天前 | Linux · mount namespace unshare Linux挂载隔离
- mount namespace 隔离临时挂载的操作边界
- 462浏览 收藏
-
- 文章 · linux | 2天前 | Linux · 运维 · GNU tar 增量归档 listed-incremental exclude-from CACHEDIR.TAG
- tar 增量归档排除缓存目录的参数组合
- 324浏览 收藏
-
- 文章 · linux | 4天前 | Linux · 运维 · 日志排查 · journalctl 启动日志 Boot ID --list-boots systemd日志导出
- journalctl 按启动会话筛选并导出日志
- 369浏览 收藏
-
- 文章 · linux | 4天前 | Linux · Linux防火墙 nftables verdict map 多端口策略
- nftables verdict map 组织多端口策略的规则设计
- 475浏览 收藏
-
- 文章 · linux | 4天前 | 权限控制 · 服务管理 · systemd socket激活 systemd.socket ListenStream Accept
- systemd socket 激活服务的依赖与监听配置
- 229浏览 收藏
-
- 文章 · linux | 5天前 |
- Linux ip rule 怎么按来源地址选择路由表
- 347浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 316次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 374次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 370次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 336次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 162次使用
-
- 详解golang执行Linuxshell命令完整场景下的使用方法
- 2023-01-07 426浏览
-
- go程序部署到linux上运行的实现方法
- 2023-01-02 387浏览
-
- Linux系统下Go语言开发环境搭建
- 2023-01-07 242浏览
-
- 使用golang获取linux上文件的访问/创建/修改时间
- 2022-12-31 238浏览
-
- 在Linux系统中安装Go语言的详细教程
- 2022-12-29 402浏览

