限制 systemd 服务的多个实例的总内存使用量

限制 systemd 服务的多个实例的总内存使用量

我正在 Ubuntu 16.04(即将成为 18.04)下运行一些 .NET Core 进程作为 systemd 服务。我有一个 systemd 配置文件 ( ),如下所示:/lib/systemd/system/[email protected]

[Unit]
Description=My Service %i

[Service]
Type=simple
User=myservice
EnvironmentFile=/etc/environment
WorkingDirectory=/home/myservice/instances/%i
ExecStart=/opt/dotnet/dotnet My.Service.dll

[Install]
WantedBy=multi-user.target

我想限制全部的RAM 量全部该服务的实例可以使用。我不想将任何单个实例的 RAM 限制为小于该值,因此诸如MemoryHigh和 之类的设置MemoryMax没有帮助。

我知道 systemd 为服务模板创建了一个 cgroup,因此我想以某种方式更改该 cgroup 的内存限制。

在 Ubuntu 18.04 上,我可以手动编辑/sys/fs/cgroup/memory/system.slice/system-myservice.slice/memory.limit_in_bytes,这基本上可以满足我的要求(当总内存使用量超过限制时,进程会被终止),但这种方法存在一些问题:

  • 在服务启动之前,该文件并不总是在启动时存在。
  • 在 Ubuntu 18.04 上,每当systemctl daemon-reload调用此文件时,该文件都会被覆盖。
  • 尝试写入文件有时会返回write error: Device or resource busy

(在 Ubuntu 16.04 下,每当我的服务启动时,限制似乎都会重置,因此没有任何效果。)

有没有办法让 systemd 本身设置这个值,这样我就不必对抗它?或者有其他方法来限制一组进程的总内存使用?它们都以同一用户身份运行,因此可以限制该用户使用的 RAM,例如。

我什至尝试手动创建一个 cgroup ( cgcreate -t myservice:myservice -g memory:mycgroup),然后将ExecStart服务配置更改为/usr/bin/cgexec -g memory:mycgroup /opt/dotnet/dotnet My.Service.dll,这又可以工作,但不可靠:我编写的内存限制memory.limit_in_bytes在某个时候被重置,我不知道何时或为什么。

答案1

我终于成功了!诀窍是创建我自己的切片并将其设置在服务文件中,如下所示:

[Service]
# Everything else as in the original question
Slice=my_service_limit.slice

并创建一个切片单元文件/lib/systemd/system/my_service_limit.slice,如下所示:

[Unit]
Description=Slice that limits memory for all my services

[Slice]
# MemoryHigh works only in "unified" cgroups mode, NOT in "hybrid" mode
MemoryHigh=500M
# MemoryMax works in "hybrid" cgroups mode, too
MemoryMax=600M

笔记:请小心切片的命名,就像-层次结构分隔符一样,如中所述https://systemd.io/CGROUP_DELEGATION- 对于任何尝试配置此功能的人来说,这是一个非常有用的页面。您可以通过查看输出来检查服务是否真正使用配置的切片systemctl status myservice- 它应该显示:

  CGroup: /my_service_limit.slice/[email protected]

没有必要设置systemd.unified_cgroup_hierarchy=1(根据松本龙太郎的答案)让 MemoryMax 能够工作,但是它曾是MemoryHigh 所必需的 - 即使在“混合”模式(Ubuntu 18.04 中的默认模式)下,它也会被默默地忽略。

另外值得注意的是,这些仅适用于所使用的物理 RAM - 它们确实如此不是包括使用的交换空间。 (似乎有一个单独的 MemorySwapMax 设置,但没有 MemorySwapHigh。)

答案2

我们可能需要使用“统一的 cgroup 层次结构”,如下所示 统一和遗留控制组层次结构

要启用此功能,请将 systemd.unified_cgroup_hierarchy=1 添加到GRUB_CMDLINE_LINUX_DEFAULTin 中/etc/default/grub,运行update-grub,然后重新启动 Linux。

systemd.unified_cgroup_hierarchy解释为systemd unified cgroup hierarchy

[Service]然后在systemd 单元文件的部分添加以下行,然后运行systemctl daemon-reload

Delegate=memory
MemoryHigh=8G (if you choose 8 gigabytes as the limit)

“MemoryHigh”的解释位于 systemd.resource-control

相关内容