使用 systemd 中的 cgroups 管理资源

Cgroups 按应用程序而不是构成应用程序的各个进程来管理资源。
118 位读者喜欢这篇文章。
Business woman on laptop sitting in front of window

图片来源:Mapbox Uncharted ERG, CC-BY 3.0 US

作为系统管理员,对我来说,最令人沮丧的事情莫过于意外地耗尽计算资源。我不止一次遇到过分区磁盘空间被完全填满、RAM 耗尽以及没有足够的 CPU 时间来在合理的时间内完成任务的情况。资源管理是系统管理员最重要的任务之一。

资源管理的目的是确保所有进程都能相对平等地访问它们所需的系统资源。资源管理还包括确保在必要时添加 RAM、硬盘空间和 CPU 容量,或者在不可能的情况下进行配给。此外,应阻止有意或无意占用系统资源的用户这样做。

有些工具使系统管理员能够监控和管理各种系统资源。例如,top 和类似的工具允许您监控内存、I/O、存储(磁盘、SSD 等)、网络、交换空间、CPU 使用率等等的使用情况。这些工具,特别是那些以 CPU 为中心的工具,主要基于正在运行的进程是控制单元的范例。在最好的情况下,它们提供了一种调整 nice 值(从而调整优先级)或终止正在运行的进程的方法。(有关 nice 值的信息,请参阅使用 Glances 监控 Linux 和 Windows 主机。)

在 SystemV 环境中,基于传统资源管理的其他工具由 /etc/security/limits.conf 文件和位于 /etc/security/limits.d 目录中的本地配置文件管理。资源可以通过用户或组以相当粗糙但有用的方式进行限制。可以管理的资源包括 RAM 的各个方面、每天的总 CPU 时间、总数据量、优先级、nice 值、并发登录数、进程数、最大文件大小等等。

使用 cgroups 进行进程管理

systemd 和 SystemV 之间的一个主要区别在于它们如何处理进程。SystemV 将每个进程视为独立的实体。systemd 将相关进程收集到控制组中,称为 cgroups(控制组的缩写),并作为一个整体管理 cgroup 的系统资源。这意味着可以按应用程序而不是构成应用程序的各个进程来管理资源。

cgroup 的控制单元称为 slice 单元。Slice 是一种概念化,它允许 systemd 以树形格式对进程进行排序,以便于管理。

查看 cgroups

我将从一些命令开始,这些命令允许您查看有关 cgroups 的各种类型的信息。systemctl status <service> 命令显示有关指定服务的 slice 信息,包括其 slice。此示例显示了 at 守护程序

[root@testvm1 ~]# systemctl status atd.service
● atd.service - Deferred execution scheduler
     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2020-09-23 12:18:24 EDT; 1 day 3h ago
       Docs: man:atd(8)
   Main PID: 1010 (atd)
      Tasks: 1 (limit: 14760)
     Memory: 440.0K
        CPU: 5ms
     CGroup: /system.slice/atd.service
             └─1010 /usr/sbin/atd -f

Sep 23 12:18:24 testvm1.both.org systemd[1]: Started Deferred execution scheduler.
[root@testvm1 ~]#

这是我发现 systemd 比 SystemV 和旧的 init 程序更易用的一个重要原因。这里的信息比 SystemV 能够提供的多得多。cgroup 条目包括层级结构,其中 system.slice 是 systemd (PID 1),而 atd.service 低一级,是 system.slice 的一部分。cgroup 条目的第二行还显示了进程 ID (PID) 和用于启动守护程序的命令。

systemctl 命令显示多个 cgroup 条目。--all 选项显示所有 slice,包括当前未激活的 slice

[root@testvm1 ~]# systemctl -t slice --all
  UNIT                             LOAD   ACTIVE   SUB    DESCRIPTION                     
  -.slice                          loaded active   active Root Slice                      
  system-getty.slice               loaded active   active system-getty.slice              
  system-lvm2\x2dpvscan.slice      loaded active   active system-lvm2\x2dpvscan.slice     
  system-modprobe.slice            loaded active   active system-modprobe.slice           
  system-sshd\x2dkeygen.slice      loaded active   active system-sshd\x2dkeygen.slice     
  system-systemd\x2dcoredump.slice loaded inactive dead   system-systemd\x2dcoredump.slice
  system-systemd\x2dfsck.slice     loaded active   active system-systemd\x2dfsck.slice    
  system.slice                     loaded active   active System Slice                    
  user-0.slice                     loaded active   active User Slice of UID 0             
  user-1000.slice                  loaded active   active User Slice of UID 1000          
  user.slice                       loaded active   active User and Session Slice          

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

11 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
[root@testvm1 ~]#

关于此数据,首先要注意的是,它显示了 UID 0(root)和 1000(我的用户登录名)的用户 slice。这仅显示 slice,而不显示每个 slice 的服务。此数据表明,在用户登录时会为每个用户创建一个 slice。这可以提供一种将用户的所有任务作为一个 cgroup 实体进行管理的方法。

探索 cgroup 层次结构

到目前为止一切都很好,但 cgroup 是分层的,所有服务单元都作为 cgroup 之一的成员运行。查看该层次结构很容易,可以使用一个旧命令和一个新的 systemd 命令。

ps 命令可用于映射进程及其在 cgroup 层次结构中的位置。请注意,使用 ps 命令时,必须指定所需的数据列。我大大减少了此命令的输出量,但我试图留下足够的信息,以便您可以了解在您的系统上可能会找到什么

[root@testvm1 ~]# ps xawf -eo pid,user,cgroup,args
    PID USER     CGROUP                      COMMAND
      2 root     -                           [kthreadd]
      3 root     -                            \_ [rcu_gp]
      4 root     -                            \_ [rcu_par_gp]
      6 root     -                            \_ [kworker/0:0H-kblockd]
      9 root     -                            \_ [mm_percpu_wq]
     10 root     -                            \_ [ksoftirqd/0]
     11 root     -                            \_ [rcu_sched]
     12 root     -                            \_ [migration/0]
     13 root     -                            \_ [cpuhp/0]
     14 root     -                            \_ [cpuhp/1]
<SNIP>
 625406 root     -                            \_ [kworker/3:0-ata_sff]
 625409 root     -                            \_ [kworker/u8:0-events_unbound]
      1 root     0::/init.scope              /usr/lib/systemd/systemd --switched-root --system --deserialize 30
    588 root     0::/system.slice/systemd-jo /usr/lib/systemd/systemd-journald
    599 root     0::/system.slice/systemd-ud /usr/lib/systemd/systemd-udevd
    741 root     0::/system.slice/auditd.ser /sbin/auditd
    743 root     0::/system.slice/auditd.ser  \_ /usr/sbin/sedispatch
    764 root     0::/system.slice/ModemManag /usr/sbin/ModemManager
    765 root     0::/system.slice/NetworkMan /usr/sbin/NetworkManager --no-daemon
    767 root     0::/system.slice/irqbalance /usr/sbin/irqbalance --foreground
    779 root     0::/system.slice/mcelog.ser /usr/sbin/mcelog --ignorenodev --daemon --foreground
    781 root     0::/system.slice/rngd.servi /sbin/rngd -f
    782 root     0::/system.slice/rsyslog.se /usr/sbin/rsyslogd -n
<SNIP>
    893 root     0::/system.slice/sshd.servi sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
   1130 root     0::/user.slice/user-0.slice  \_ sshd: root [priv]
   1147 root     0::/user.slice/user-0.slice  |   \_ sshd: root@pts/0
   1148 root     0::/user.slice/user-0.slice  |       \_ -bash
   1321 root     0::/user.slice/user-0.slice  |           \_ screen
   1322 root     0::/user.slice/user-0.slice  |               \_ SCREEN
   1323 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 498801 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.resource-control
 498813 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1351 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 123293 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.slice
 123305 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1380 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625412 root     0::/user.slice/user-0.slice  |                   |   \_ ps xawf -eo pid,user,cgroup,args
 625413 root     0::/user.slice/user-0.slice  |                   |   \_ less
 246795 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625338 root     0::/user.slice/user-0.slice  |                       \_ /usr/bin/mc -P /var/tmp/mc-root/mc.pwd.246795
 625340 root     0::/user.slice/user-0.slice  |                           \_ bash -rcfile .bashrc
   1218 root     0::/user.slice/user-1000.sl  \_ sshd: dboth [priv]
   1233 dboth    0::/user.slice/user-1000.sl      \_ sshd: dboth@pts/1
   1235 dboth    0::/user.slice/user-1000.sl          \_ -bash
<SNIP>
   1010 root     0::/system.slice/atd.servic /usr/sbin/atd -f
   1011 root     0::/system.slice/crond.serv /usr/sbin/crond -n
   1098 root     0::/system.slice/lxdm.servi /usr/sbin/lxdm-binary
   1106 root     0::/system.slice/lxdm.servi  \_ /usr/libexec/Xorg -background none :0 vt01 -nolisten tcp -novtswitch -auth /var/run/lxdm/lxdm-:0.auth
 370621 root     0::/user.slice/user-1000.sl  \_ /usr/libexec/lxdm-session
 370631 dboth    0::/user.slice/user-1000.sl      \_ xfce4-session
 370841 dboth    0::/user.slice/user-1000.sl          \_ /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
 370911 dboth    0::/user.slice/user-1000.sl          \_ xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
 370930 dboth    0::/user.slice/user-1000.sl          \_ xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
 370942 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libsystray.so 6 23068680 systr
ay Notification Area Area where notification icons appear
 370943 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libpulseaudio-plugin.so 8 2306
8681 pulseaudio PulseAudio Plugin Adjust the audio volume of the PulseAudio sound system
 370944 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libxfce4powermanager.so 9 2306
8682 power-manager-plugin Power Manager Plugin Display the battery levels of your devices and control the brightness of your display
 370945 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libnotification-plugin.so 10 2
3068683 notification-plugin Notification Plugin Notification plugin for the Xfce panel
 370948 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libactions.so 14 23068684 acti
ons Action Buttons Log out, lock or other system actions
 370934 dboth    0::/user.slice/user-1000.sl          \_ Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
 370939 dboth    0::/user.slice/user-1000.sl          \_ xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
 370962 dboth    0::/user.slice/user-1000.sl          \_ nm-applet
<SNIP>

您可以使用 systemd-cgls 命令查看整个层次结构,这更简单,因为它不需要任何复杂的选项。

我也大大缩短了这个树状视图。但是,我留下了足够的信息,以便您了解数据量以及在系统上执行此操作时应看到的条目类型。我在我的一个虚拟机上执行了此操作,大约有 200 行;我的主工作站的数据量约为 250 行

[root@testvm1 ~]# systemd-cgls
Control group /:
-.slice
├─user.slice 
│ ├─user-0.slice 
│ │ ├─session-1.scope 
│ │ │ ├─  1130 sshd: root [priv]
│ │ │ ├─  1147 sshd: root@pts/0
│ │ │ ├─  1148 -bash
│ │ │ ├─  1321 screen
│ │ │ ├─  1322 SCREEN
│ │ │ ├─  1323 /bin/bash
│ │ │ ├─  1351 /bin/bash
│ │ │ ├─  1380 /bin/bash
│ │ │ ├─123293 man systemd.slice
│ │ │ ├─123305 less
│ │ │ ├─246795 /bin/bash
│ │ │ ├─371371 man systemd-cgls
│ │ │ ├─371383 less
│ │ │ ├─371469 systemd-cgls
│ │ │ └─371470 less
│ │ └─user@0.service …
│ │   ├─dbus-broker.service 
│ │   │ ├─1170 /usr/bin/dbus-broker-launch --scope user
│ │   │ └─1171 dbus-broker --log 4 --controller 12 --machine-id 3bccd1140fca488187f8a1439c832f07 --max-bytes 100000000000000 --max-fds 25000000000000 --max->
│ │   ├─gvfs-daemon.service 
│ │   │ └─1173 /usr/libexec/gvfsd
│ │   └─init.scope 
│ │     ├─1137 /usr/lib/systemd/systemd --user
│ │     └─1138 (sd-pam)
│ └─user-1000.slice 
│   ├─user@1000.service …
│   │ ├─dbus\x2d:1.2\x2dorg.xfce.Xfconf.slice 
│   │ │ └─dbus-:1.2-org.xfce.Xfconf@0.service 
│   │ │   └─370748 /usr/lib64/xfce4/xfconf/xfconfd
│   │ ├─dbus\x2d:1.2\x2dca.desrt.dconf.slice 
│   │ │ └─dbus-:1.2-ca.desrt.dconf@0.service 
│   │ │   └─371262 /usr/libexec/dconf-service
│   │ ├─dbus-broker.service 
│   │ │ ├─1260 /usr/bin/dbus-broker-launch --scope user
│   │ │ └─1261 dbus-broker --log 4 --controller 11 --machine-id 
<SNIP>
│   │ └─gvfs-mtp-volume-monitor.service 
│   │   └─370987 /usr/libexec/gvfs-mtp-volume-monitor
│   ├─session-3.scope 
│   │ ├─1218 sshd: dboth [priv]
│   │ ├─1233 sshd: dboth@pts/1
│   │ └─1235 -bash
│   └─session-7.scope 
│     ├─370621 /usr/libexec/lxdm-session
│     ├─370631 xfce4-session
│     ├─370805 /usr/bin/VBoxClient --clipboard
│     ├─370806 /usr/bin/VBoxClient --clipboard
│     ├─370817 /usr/bin/VBoxClient --seamless
│     ├─370818 /usr/bin/VBoxClient --seamless
│     ├─370824 /usr/bin/VBoxClient --draganddrop
│     ├─370825 /usr/bin/VBoxClient --draganddrop
│     ├─370841 /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
│     ├─370910 /bin/gpg-agent --sh --daemon --write-env-file /home/dboth/.cache/gpg-agent-info
│     ├─370911 xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
│     ├─370923 xfsettingsd --display :0.0 --sm-client-id 261b4a437-3029-461c-9551-68c2c42f4fef
│     ├─370930 xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
│     ├─370934 Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
│     ├─370939 xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
<SNIP>
└─system.slice 
  ├─rngd.service 
  │ └─1650 /sbin/rngd -f
  ├─irqbalance.service 
  │ └─1631 /usr/sbin/irqbalance --foreground
  ├─fprintd.service 
  │ └─303383 /usr/libexec/fprintd
  ├─systemd-udevd.service 
  │ └─956 /usr/lib/systemd/systemd-udevd
<SNIP>
  ├─systemd-journald.service 
  │ └─588 /usr/lib/systemd/systemd-journald
  ├─atd.service 
  │ └─1010 /usr/sbin/atd -f
  ├─system-dbus\x2d:1.10\x2dorg.freedesktop.problems.slice 
  │ └─dbus-:1.10-org.freedesktop.problems@0.service 
  │   └─371197 /usr/sbin/abrt-dbus -t133
  ├─sshd.service 
  │ └─893 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
  ├─vboxservice.service 
  │ └─802 /usr/sbin/VBoxService -f
  ├─crond.service 
  │ └─1011 /usr/sbin/crond -n
  ├─NetworkManager.service 
  │ └─765 /usr/sbin/NetworkManager --no-daemon
  ├─switcheroo-control.service 
  │ └─787 /usr/libexec/switcheroo-control
 <SNIP>

此树状视图显示了所有用户 slice 和系统 slice,以及在每个 cgroup 中运行的服务和程序。请注意名为“scopes”的单元,它们将相关程序分组到一个管理单元中,在上面列表中的 user-1000.slice 中。user-1000.slice/session-7.scope cgroup 包含 GUI 桌面程序层次结构,从 LXDM 显示管理器会话及其所有子任务开始,包括诸如 Bash shell 和 Thunar GUI 文件管理器之类的东西。

Scope 单元未在配置文件中定义,而是作为启动相关程序组的结果以编程方式生成的。Scope 单元不创建或启动作为该 cgroup 一部分运行的进程。Scope 内的所有进程都是平等的,没有内部层次结构。Scope 的生命周期从第一个进程创建时开始,到最后一个进程销毁时结束。

在您的桌面上打开多个窗口,例如终端模拟器、LibreOffice 或任何您想要的东西,然后切换到可用的虚拟控制台并启动诸如 topMidnight Commander 之类的程序。在您的主机上运行 systemd-cgls 命令,并注意整体层次结构和 scope 单元。

与我发现的任何其他命令相比,systemd-cgls 命令提供了更完整的 cgroup 层次结构表示(以及构成它的单元的详细信息)。我更喜欢它比 ps 命令提供的更简洁的树状表示。

在我的朋友们的帮助下

在介绍了这些基础知识之后,我本计划更详细地介绍 cgroup 以及如何使用它们,但我发现了 Red Hat 的 Steve Ovens 在 Opensource.com 的姊妹站点 Enable Sysadmin 上发表的一系列四篇优秀文章。与其基本上重写 Steve 的文章,我决定利用他对 cgroup 的专业知识,链接到它们会更好

  1. Linux 系统管理员的 cgroup 入门
  2. 如何使用 CPUShares 管理 cgroup
  3. 以艰难的方式管理 cgroup—手动
  4. 使用 systemd 管理 cgroup

像我一样享受并从中学习。

其他资源

互联网上有大量关于 systemd 的信息,但其中许多信息简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了关于 systemd 启动的更详细和可靠的信息。自从我开始撰写本系列文章以来,此列表不断增长,以反映我所做的研究。

  • Fedora 项目有一个很好的实用指南 关于 systemd。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
  • Fedora 项目还有一个很好的速查表,其中将旧的 SystemV 命令与可比较的 systemd 命令进行交叉引用。
  • systemd.unit(5) 手册页包含一个很好的单元文件部分及其配置选项列表,以及每个选项的简洁描述。
  • Red Hat 文档包含对单元文件结构以及其他重要信息的良好描述。
  • 有关 systemd 的详细技术信息以及创建它的原因,请查看 Freedesktop.org 的systemd 描述。此页面是我找到的最好的页面之一,因为它包含许多指向其他重要且准确文档的链接。
  • Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧
  • 请参阅 systemd.resource-control(5) 的手册页。
  • Linux 内核用户和管理员指南中,请参阅 Control Group v2 条目。

Lennart Poettering(systemd 的设计者和主要开发人员)还为 Linux 系统管理员撰写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在和当时一样具有相关性。关于 systemd 及其生态系统的所有其他优秀著作都基于这些论文。

接下来阅读什么
David Both
David Both 是一位开源软件和 GNU/Linux 倡导者、培训师、作家和演讲者。自 1996 年以来,他一直从事 Linux 和开源软件方面的工作,自 1969 年以来一直从事计算机方面的工作。他是“系统管理员 Linux 哲学”的坚定支持者和传播者。

评论已关闭。

© . All rights reserved.