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

EM0*_*EM0 6 linux ubuntu memory systemd cgroups

我在 Ubuntu 16.04(即将推出 18.04)下运行一些 .NET Core 进程作为 systemd 服务。我有一个 systemd 配置文件 ( /lib/systemd/system/myservice@.service),如下所示:

[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
Run Code Online (Sandbox Code Playgroud)

我想限制此服务的所有实例可以使用的 RAM总量。我不想将任何单个实例的 RAM 限制为小于该值,因此类似的设置并没有帮助。MemoryHighMemoryMax

我知道 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在某个时候被重置,我不知道何时或为什么。

EM0*_*EM0 5

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

[Service]
# Everything else as in the original question
Slice=my_service_limit.slice
Run Code Online (Sandbox Code Playgroud)

并创建一个切片单元文件/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
Run Code Online (Sandbox Code Playgroud)

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

  CGroup: /my_service_limit.slice/myservice@myinstance.service
Run Code Online (Sandbox Code Playgroud)

没有必要设置systemd.unified_cgroup_hierarchy=1(根据Ryutaroh Matsumoto的回答)MemoryMax 才能工作,但MemoryHigh必要的 - 即使在“混合”模式(Ubuntu 18.04 中的默认模式)下,它也会被默默地忽略。

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


Ryu*_*oto 1

我们可能需要使用“统一的 cgroup 层次结构”,如 Unified and Legacy Control Group Hierarchies 中所述。

要启用此功能,请将 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)
Run Code Online (Sandbox Code Playgroud)

“MemoryHigh”的解释在 中给出 systemd.resource-control