Red Hat Training

A Red Hat training course is available for Red Hat Linux

1.2. cgroup 的默认层级

默认情况下,systemd 会自动创建 slicescopeservice 单位的层级,来为 cgroup 树提供统一结构。使用 systemctl 指令,您可以通过创建自定义 slice 进一步修改此结构,详情请参阅〈第 2.1 节 “创建控制群组”〉。systemd 也自动为 /sys/fs/cgroup/ 目录中重要的 kernel 资源管控器(参见〈Red Hat Enterprise Linux 7 中可用的管控器〉)挂载层级。

警告

虽然不推荐使用 libcgroup 软件包中的 cgconfig 工具,但它可以为 systemd (尤其是 net-prio 管控器)暂不支持的管控器挂载、处理层级。永远不要使用 libcgropup 工具去修改 systemd 默认挂载的层级,否则可能会导致异常情况。在 Red Hat Enterprise Linux 后续版本中,libcgroup 软件库将会被移除。更多关于如何使用 cgconfig 的信息,请参考〈第 3 章 使用 libcgroup 工具〉。

systemd 的单位类型

系统中运行的所有进程,都是 systemd init 进程的子进程。在资源管控方面,systemd 提供了三种单位类型(如需 systemd 单位类型完整列表,请参阅《Red Hat Enterprise Linux 7 系统管理员指南 · 使用 systemd 管理 service》):
  • service —— 一个或一组进程,由 systemd 依据单位配置文件启动。service 对指定进程进行封装,这样进程可以作为一个整体被启动或终止。service 参照以下方式命名:
    name.service
    其中,name 代表服务名称。
  • scope —— 一组外部创建的进程。由强制进程通过 fork() 函数启动和终止、之后被 systemd 在运行时注册的进程,scope 会将其封装。例如:用户会话、 容器和虚拟机被认为是 scope。scope 的命名方式如下:
    name.scope
    其中,name 代表 scope 名称。
  • slice —— 一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。真正的进程包含在 scope 或 service 中。在这一被划分层级的树中,每一个 slice 单位的名字对应通向层级中一个位置的路径。小横线("-")起分离路径组件的作用。例如,如果一个 slice 的名字是:
    parent-name.slice
    这说明 parent-name.sliceparent.slice 的一个子 slice。这一子 slice 可以再拥有自己的子 slice,被命名为:parent-name-name2.slice,以此类推。
    根 slice 的表示方式:
    -.slice
service、scope 和 slice 单位直接映射到 cgroup 树中的对象。当这些单位被激活,它们会直接一一映射到由单位名建立的 cgroup 路径中。例如,ex.service 属于 test-waldo.slice,会直接映射到 cgroup test.slice/test-waldo.slice/ex.service/ 中。
service、scope 和 slice 是由系统管理员手动创建或者由程序动态创建的。默认情况下, 操作系统会定义一些运行系统必要的内置 service。另外,默认情况下,系统会创建四种 slice:
  • -.slice —— 根 slice;
  • system.slice —— 所有系统 service 的默认位置;
  • user.slice —— 所有用户会话的默认位置;
  • machine.slice —— 所有虚拟机和 Linux 容器的默认位置。
请注意,所有的用户会话、虚拟机和容器进程会被自动放置在一个单独的 scope 单元中。而且,所有的用户会分得一个隐含子 slice(implicit subslice)。除了上述的默认配置,系统管理员可能会定义新的 slice,并将 service 和 scope 置于其中。
以下是一个 cgroup 树的简化例子。使用〈第 2.4 节 “获得关于控制群组的信息”〉中记述的 systemd-cgls 指令,这一输出就会出现:
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 20  
├─user.slice
│ └─user-1000.slice
│   └─session-1.scope
│     ├─11459 gdm-session-worker [pam/gdm-password]
│     ├─11471 gnome-session --session gnome-classic
│     ├─11479 dbus-launch --sh-syntax --exit-with-session
│     ├─11480 /bin/dbus-daemon --fork --print-pid 4 --print-address 6 --session
│     ...
│     
└─system.slice
  ├─systemd-journald.service
  │ └─422 /usr/lib/systemd/systemd-journald
  ├─bluetooth.service
  │ └─11691 /usr/sbin/bluetoothd -n
  ├─systemd-localed.service
  │ └─5328 /usr/lib/systemd/systemd-localed
  ├─colord.service
  │ └─5001 /usr/libexec/colord
  ├─sshd.service
  │ └─1191 /usr/sbin/sshd -D
  │ 
  ...
如您所见,service 和 scope 包含进程,但被放置在不包含它们自身进程的 slice 里。唯一例外是位于特殊 systemd.slice 中的 PID 1。请注意,-.slice 未被显示,因为它被整体树的根隐性识别。
service 和 slice 单位可通过〈第 2.3.2 节 “修改单位文件”〉中的永久单位文件来配置;或者对 PID 1 进行 API 调用(如需要 API 的详细信息,请参阅〈“在线文档 ”一节〉),在运行时动态创建。scope 单位只能以第一种方式创建。API 调用动态创建的单位是临时的,并且仅在运行时存在。一旦结束、被关闭或者系统重启,临时单位会被自动释放。