Linux cgroup v2 限制服务 CPU 与内存的完整思路
给 Linux 服务限制 CPU 和内存,先确定服务属于哪一层 cgroup,再分别处理“持续分配”“压力降级”和“硬性终止”。生产环境里我更倾向于让 systemd 管理边界:用 CPUQuota= 限制 CPU 时间,用 MemoryHigh= 给内存回收压力设边界,再用 MemoryMax= 兜住最坏情况。
官方资料:https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html systemd 资源控制:https://cgit.freedesktop.org/systemd/systemd/tree/man/systemd.resource-control.xml
- 先确认
cgroup.controllers是否提供cpu和memory,控制器按父子层级向下生效。 CPUQuota是带宽上限,MemoryHigh是压力边界,MemoryMax才是硬内存上限。- 配置后要同时看服务状态、
cpu.stat、memory.current和memory.events,否则很难区分限流和故障。
先把服务放进可解释的 cgroup 层级
cgroup v2 是统一层级。父级启用控制器后,子级才能继续分配;父级的限制也不能被更深的子级抵消。直接改文件前,先确认挂载类型和控制器可用性:
# 确认目标路径是统一 cgroup v2 文件系统 stat -fc %T /sys/fs/cgroup # 查看根级可用控制器,缺少 cpu 或 memory 时不要继续写对应文件 cat /sys/fs/cgroup/cgroup.controllers # 查看根级已经向子层级开放的控制器 cat /sys/fs/cgroup/cgroup.subtree_control
文件不存在不一定是权限问题:控制器可能没有在父级开启,也可能仍由旧的 v1 层级管理。

把预算拆成 CPU 上限、内存压力和硬边界
CPU 和内存的语义不同,不能只按机器总配置平均切一刀。CPU 看高峰处理速率,内存要给运行时、缓存和突发分配留余量。
| 目标 | systemd 配置 | 底层接口 | 判断方式 |
|---|---|---|---|
| 限制 CPU 带宽 | CPUQuota=50% | cpu.max | 观察 nr_throttled |
| 降低内存回收冲击 | MemoryHigh=512M | memory.high | 看回收压力与延迟 |
| 兜住最坏内存占用 | MemoryMax=768M | memory.max | 检查 oom 事件 |
| 相对分配权重 | CPUWeight=200 | cpu.weight | 只比较同层竞争者 |
CPUQuota=50% 表示最多使用一个 CPU 的一半时间,超过 100% 才允许跨多个 CPU 累计使用。内核的 cpu.max 采用“最大带宽 + 周期”格式,例如 50000 100000。MemoryHigh 主要带来回收和节流压力,MemoryMax 才是硬限制。
用 systemd drop-in 持久配置服务边界
假设服务名为 demo.service,用 drop-in 管理资源参数,便于审查和回滚:
# /etc/systemd/system/demo.service.d/resources.conf [Service] # 以单个 CPU 为基准限制总 CPU 时间,避免突发任务长期抢占 CPUQuota=50% # 先让内存进入回收压力区,给服务留出自我收缩机会 MemoryHigh=512M # 最坏情况下限制该服务及其子进程的内存总量 MemoryMax=768M # 只在同一父级的服务之间调整相对 CPU 权重 CPUWeight=200
# 让 systemd 重新读取 drop-in,再重启目标服务 sudo systemctl daemon-reload sudo systemctl restart demo.service # 查看最终合并后的资源配置和服务所在层级 systemctl show demo.service -p ControlGroup -p CPUQuotaPerSecUSec -p MemoryHigh -p MemoryMax
数值只是示例,上线前应以压测峰值、延迟预算和降级策略反推;出现超时,要确认缓存、子进程或日志侧车是否也算进了该 cgroup。
限制生效后要看什么
只看 systemctl status 不够。CPU 看累计使用与 throttling 计数;内存区分当前占用、high 压力和 max 事件:
# 取出 systemd 展开的 cgroup 相对路径
cg=$(systemctl show -p ControlGroup --value demo.service)
# 读取 CPU 使用与被节流的累计计数
cat "/sys/fs/cgroup${cg}/cpu.stat"
# 读取当前内存占用及内存事件计数
cat "/sys/fs/cgroup${cg}/memory.current"
cat "/sys/fs/cgroup${cg}/memory.events"
nr_throttled 持续增长,先检查 CPU 配额或线程池;high 增长,说明回收压力已影响服务;oom 或 oom_kill 增长,则回退 MemoryMax、减少缓存或拆分子层级。ControlGroup 是相对 /sys/fs/cgroup 的路径,不是固定值。

直接操作 cgroup v2 时的边界
手工写 cpu.max、memory.high 或 memory.max 适合容器运行时、批处理沙箱和动态控制器,但要先创建子 cgroup、迁移进程,再按父级允许的控制器配置。不要让 systemd 和手工脚本同时争夺同一个目录。
需要把资源控制权交给服务内部的容器管理器时,才考虑 systemd 的 Delegate=。它代表允许服务在自己的控制组下继续建立子层级,并不意味着服务可以突破父级的资源限制。委派前要明确谁负责创建子组、谁负责清理以及谁读取事件。
常见问题
CPUQuota 和 CPUWeight 应该二选一吗?
不必。Quota 是绝对带宽上限,Weight 是同层竞争时的相对分配;低优先级服务可以两者同时设置,但不要用 Weight 代替硬上限。
MemoryHigh 超出后会立即杀进程吗?
不会。它主要触发回收和节流压力;需要硬性兜底时再设置 MemoryMax,并为 OOM 后的恢复或降级准备方案。
为什么子 cgroup 里没有 cpu.max?
先看父级的 cgroup.controllers 和 cgroup.subtree_control。控制器只有在父级可用并向子层级开启后,子目录才会出现相应接口。
为上传接口设置请求体上限并正确清理临时文件
- 上一篇
- 为上传接口设置请求体上限并正确清理临时文件
- 下一篇
- 用 CSS Container Query 让卡片按容器而不是视口响应
-
- 文章 · linux | 4小时前 |
- systemd 服务里的 LimitNOFILE 为什么和 shell ulimit 不同
- 258浏览 收藏
-
- 文章 · linux | 9小时前 | Linux Rsync 断点续传 partial-dir
- rsync partial-dir 怎么保留中断的大文件传输
- 294浏览 收藏
-
- 文章 · linux | 1天前 | Linux · 磁盘空间 · 日志清理 journalctl systemd journal vacuum-size vacuum-time
- journalctl 按容量和时间清理归档日志怎么组合
- 321浏览 收藏
-
- 文章 · linux | 1天前 | 定时任务 · Linux · 运维 · Linux OnCalendar Persistent systemd timer
- systemd timer 的 Persistent 为什么能补跑错过任务
- 294浏览 收藏
-
- 文章 · linux | 1天前 | Linux · 故障排查 · Linux GDB coredumpctl systemd-coredump
- coredumpctl 怎么把指定崩溃导出给调试器
- 233浏览 收藏
-
- 文章 · linux | 1天前 | Linux · 运维 · journalctl journald持久化 systemd日志 Storage persistent 重启日志
- journald 怎么把重启前的日志持久化到磁盘
- 166浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 358次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 416次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 428次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 381次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 207次使用
-
- 详解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浏览

