用 systemd-run 临时限制脚本内存与 CPU,避免拖垮系统
用 systemd-run 临时限制脚本资源
问题场景
在开发或运维中,经常需要运行一些来源不确定、可能内存泄漏或吃满 CPU 的脚本。例如一个批量处理数据的临时脚本,或者第三方提供的工具。如果直接在前台或后台运行,它可能不断申请内存,最终触发系统 OOM,把重要服务一起拖垮。永久修改 systemd 服务或 cgroup 配置又太重,且不适合一次性任务。此时可以用 systemd-run 创建临时 cgroup,给进程套上资源限额,用完即走。
解决思路
systemd-run 可以启动一个 transient unit(临时服务或 scope),并通过 -p 传入资源控制属性。常用的两个属性:
MemoryMax=512M:硬内存上限,超过后 cgroup 内进程可能被 OOM killer 终止。CPUQuota=50%:CPU 配额,表示最多使用半个 CPU 核心的计算时间。
这两个属性由 systemd 的资源控制框架管理,底层是 cgroup。运行后可以用 systemd-cgtop 按内存或 CPU 查看各 cgroup 的实时占用,确认限制是否生效。
最小可运行示例
先准备一个会持续申请内存的 Python 脚本,保存为 /tmp/leak_demo.py。示例仅用于演示,请勿在生产环境随意执行:
# /tmp/leak_demo.py
import time
chunks = []
while True:
chunks.append(bytearray(10 * 1024 * 1024)) # 每次申请 10 MiB
time.sleep(0.1)
这个脚本会不断向列表里追加 10 MiB 的字节数组,内存占用持续上升。
用 systemd-run 启动它,并加上 512M 内存和 50% CPU 限制:
sudo systemd-run --unit=leak-demo -p MemoryMax=512M -p CPUQuota=50% python3 /tmp/leak_demo.py
如果当前用户已有 systemd user manager,也可以尝试 systemd-run --user,但资源控制属性是否可用取决于系统配置。没有 sudo 权限时请先确认权限边界。
启动后,unit 会在后台运行。查看状态:
systemctl status leak-demo
查看 cgroup 资源限制是否写入:
systemctl show leak-demo -p MemoryMax -p CPUQuota
预期能看到 MemoryMax=536870912(512M 的字节数)和 CPUQuota=50% 之类的输出。注意不同 systemd 版本显示格式可能不同。
用 systemd-cgtop 验证
运行:
systemd-cgtop --order=memory
或者直接运行 systemd-cgtop,然后观察 leak-demo 对应的 cgroup。按内存排序时,应该能看到它的内存占用逐渐上升,接近 512M 后不再明显增长;随后进程可能因超过硬限制被 OOM killer 终止。此时再执行:
systemctl status leak-demo
可能会看到 unit 进入 failed 状态,并提示被信号杀死或内存超限。也可以观察 CPU 列,确认它最多只消耗约一半核心的 CPU 时间。
如果只是想验证限制是否生效,而不希望进程被杀,可以先用 MemoryHigh 代替 MemoryMax,或者把脚本改成有限循环。但 MemoryHigh 是软限制,达到后主要触发回收和节流,不保证一定杀死进程。
运行方法与清理
如果 unit 还在运行,可以停止:
sudo systemctl stop leak-demo
对于 transient unit,停止后通常会自动清理。若需要彻底删除,可以:
sudo systemctl reset-failed leak-demo
边界与限制
- 环境依赖:
systemd-run、systemd-cgtop需要 Linux 上运行 systemd。容器、WSL、部分精简系统可能没有完整 systemd,命令会不可用。 - cgroup 版本:cgroup v1 与 v2 对控制器的支持不同。
MemoryMax和CPUQuota要求对应控制器已启用;如果属性不生效,需要检查内核启动参数和 systemd 配置。 - 权限:通常需要 root 或具备相应 polkit 权限。普通用户使用
--user时,资源限制能力可能受限。 - 进程行为:cgroup 会包含子进程,但如果脚本主动脱离 cgroup、创建新 session 或通过其他机制逃逸,限制可能失效。不要用它来约束恶意程序。
- OOM 影响:
MemoryMax是硬限制,超限会触发 OOM killer,可能杀死 unit 内进程。测试时不要在生产核心业务上直接使用。 - 参数占位:示例中的
512M、50%、脚本路径和 unit 名称都是占位值,请按实际需求调整。 - 临时性:
systemd-run创建的 unit 默认不持久化,重启后不会保留。如果需要长期限制,应编写正式的 unit 文件或 drop-in 配置。
小结
对于一次性、可能失控的脚本,systemd-run 提供了一种轻量的资源隔离方式:用 -p MemoryMax 和 -p CPUQuota 设置上限,再用 systemd-cgtop 观察实际占用。它不能替代完善的资源规划和监控,但在开发、测试和临时任务中可以有效降低单个进程拖垮系统的风险。
- 点赞
- 收藏
- 关注作者
评论(0)