当前位置:首页 > 文章列表 > 文章 > linux > resource-control 怎样限制服务内存

resource-control 怎样限制服务内存

来源:17golang原创 2026-10-25 14:08:02 0浏览 收藏

在 systemd 服务的 [Service] 段设置 MemoryHigh= 和 MemoryMax=,可分别建立回收节流阈值和内存兜底上限;需要约束交换空间时,再单独配置 MemorySwapMax=。本文以 cgroup v2 的内存控制器为前提,限制对象是服务所在资源组,而不是只给主进程设置一个堆大小。

我的选择是先分清“希望降低压力”和“必须控制失控范围”,再决定数值。以下预算只是原创配置示例,没有进行本机测试,也不代表适合所有服务的容量建议。

官方说明:https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html。内核接口:https://docs.kernel.org/admin-guide/cgroup-v2.html。管理命令:https://www.freedesktop.org/software/systemd/man/latest/systemctl.html。

使用场景:限制整个服务的资源范围

一个后台任务可能有主进程、子工作进程和共同使用的缓存。只看主进程 RSS,很容易漏掉同一服务资源组里的其他开销。用 resource-control 建立的是组级资源边界:服务在组内的进程及其受该层级约束的后代共同面对预算。

本文用已存在的 demo-worker.service 代指待调整服务,不提供假的可执行程序。请先把示例名换成真实单元。若实际应用由容器平台管理,应该确认该平台负责哪层 cgroup,避免只改宿主机一个无关服务。

候选方案:回收阈值、硬上限与 swap 上限

选项主要作用取舍
MemoryHigh超过阈值时施加回收和节流压力适合主要调控,但不保证绝不超出
MemoryMax约束组内内存,无法降低时可能组内 OOM适合最后防线,需接受失败风险
MemorySwapMax单独限制该组 swap 用量不是内存与 swap 相加的总额

MemoryHigh 本身不是到点杀进程的开关,过低会让服务花更多时间回收内存,表现为延迟或吞吐退化。MemoryMax 也不是应用能放心使用的“可用堆额度”;在特定情况下用量可短暂越过限制,无法回收时则可能触发组内 OOM。

因此三项可以配合使用,不能简单选一个“更强”的选项替代其他职责。MemorySwapMax=0 表达不允许该组使用 swap 的约束,但不自动解决工作集过大的问题;可回收空间减少后,容量策略仍需重新评估。

图1:服务资源组与三项内存控制接口的静态映射
图1:服务资源组与三项内存控制接口的静态映射。静态结构说明图,不是运行截图或性能结果。

对比维度:看 cgroup 统计而非单个进程

观察时区分当前组内存、swap 和事件计数。memory.current 包含被计入该组的多种内存开销,不能直接等同于单个进程的 RSS;memory.swap.current 则是另一项统计。应用自己报告的堆大小,也只是内部视角。

memory.events 中的 high、max、oom、oom_kill 有不同含义。high 增长体现触及高阈值的压力,不能据此断言发生了杀进程;oom_kill 才涉及 OOM 杀进程事件。应结合日志与业务失败情况判断,不把单个计数当成完整故障结论。

# 读取该服务实际的 cgroup 路径;本段仅针对统一 cgroup v2 挂载。
service_group=$(systemctl show demo-worker.service -p ControlGroup --value)
# 空路径时停止,避免把根组统计误认为目标服务。
if [ -z "$service_group" ] || [ "$service_group" = / ]; then
    printf '%s\n' '服务没有可用的独立 cgroup 路径' >&2
    exit 1
fi
# 这些是读取操作:当前内存、swap 和内存事件计数。
cat "/sys/fs/cgroup$service_group/memory.current"
cat "/sys/fs/cgroup$service_group/memory.swap.current"
cat "/sys/fs/cgroup$service_group/memory.events"

命令假定目标服务存在且 cgroup v2 挂载在 /sys/fs/cgroup。若路径下没有相应控制文件,应核对部署的层级、控制器可用性和命名空间。本文不建议在不了解系统管理方式时直接改写这些内核文件。

推荐选择:为现有服务添加专用 drop-in

为已有服务创建独立的 /etc/systemd/system/demo-worker.service.d/60-memory-budget.conf,避免直接编辑发行版提供的主单元文件:

[Service]
# 开启服务内存记账,便于按服务观察。
MemoryAccounting=yes
# 示例阈值:先以回收和节流施加压力。
MemoryHigh=640M
# 示例兜底:无法回收至范围内时,组内可能发生 OOM。
MemoryMax=896M
# swap 单独限制;这个示例最多允许 128 MiB。
MemorySwapMax=128M

示例让 MemoryHigh 低于 MemoryMax,给回收与业务缓冲保留区间。M 使用 1024 为基数;640M、896M 和 128M 均为演示值。真实数值应覆盖正常高峰、子进程并发、运行时堆外分配及业务允许的延迟。

# demo-worker.service 代表你已有的服务,先换成真实单元名。
sudo install -d /etc/systemd/system/demo-worker.service.d
# 把正文配置保存为该目录下的 60-memory-budget.conf,再重读定义。
sudo systemctl daemon-reload
# 在允许中断的维护窗口重启,让配置随服务启动应用。
sudo systemctl restart demo-worker.service
# 查看管理器配置值及当前记账值,数值以自己的环境为准。
systemctl show demo-worker.service -p MemoryAccounting -p MemoryCurrent -p MemoryHigh -p MemoryMax -p MemorySwapMax -p ControlGroup

这些命令是供读者在其 Linux 主机操作的步骤,本文没有执行。重启前安排维护窗口;部署后既要看配置值,也要看业务行为。设置一个阈值不会自动优化应用的数据结构,更不能代替修复持续增长的内存泄漏。

图2:服务主进程、工作进程与父 slice 的资源层级关系
图2:服务主进程、工作进程与父 slice 的资源层级关系。静态结构说明图,不是运行截图或性能结果。

不适用情况:层级限制和应用自身预算

如果父 slice 已经设置更严格的限制,子服务写一个更大的 MemoryMax 不能突破父级边界。systemd 的有效内存限制要考虑自身和祖先配置;只查看一个 drop-in 的字面值,无法解释全部可用容量。

同样,MemoryMax 不会修改 JVM、Python 扩展或其他运行时的内部预算。应用必须在组级总额里为堆、线程栈、原生分配和相关缓存预留空间。把堆上限直接等于组级硬上限,常会让辅助开销没有余地。

启动阶段和稳态需求不同也应单独考虑,但不要在缺乏负载证据时叠加大量参数。先理解当前系统支持的选项与控制器,再确定是否需要不同阶段的预算。本文不承诺给出一个跨发行版、跨业务的固定数值。

决策表与常见问题

实际需求选择思路
希望超出后先回收、容忍一定波动以 MemoryHigh 为主要调控
需要限制单服务失控影响增加有余量的 MemoryMax
需要控制交换占用单独配置 MemorySwapMax
多个服务共享总预算同时规划父 slice 和子服务约束
应用工作集持续增长保留边界,并修复应用原因

MemoryAccounting=yes 等于限制了吗?

不是。记账用于观察,限额仍由相应控制项表达。看到统计值不代表已经有合理的高阈值或硬上限。

服务没退出,是否说明阈值未生效?

不能这样判断。MemoryHigh 主要表现为回收压力和节流;硬限制触及后是否发生 OOM,也取决于能否回收以及具体分配。需要结合组统计、事件与日志。

参数会控制每个进程相同大小吗?

这里讨论的是资源组共享预算,不能把 896M 理解为每个工作进程各自可以使用 896M。并发增加时要考虑总工作集。

如何撤回示例配置?

只移除本次创建的 60-memory-budget.conf,再重读单元定义并在维护窗口按计划重启。不要为撤回一个内存设置而删除整个 drop-in 目录,里面可能还有其他运维配置;撤回后仍受父级资源约束。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
systemd-analyze security 怎样查看沙箱暴露面systemd-analyze security 怎样查看沙箱暴露面
上一篇
systemd-analyze security 怎样查看沙箱暴露面
journalctl cursor 怎样断点读取日志
下一篇
journalctl cursor 怎样断点读取日志
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    686次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    701次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    757次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    719次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    557次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码