# RHEL7 Cgroups概述

## 默认的Cgroup层次结构

默认情况下`systemd`自动创建一个`slice`（片），`scope`（范围）和`service`（服务）单元来提供cgroup树的统一结构。使用`systemctl`命令，可以通过创建定制的`slice`来修改这个层次结构。并且，`systemd`为重要的内核资源控制器在`/sys/fs/cgroup/`目录下自动挂载层次结构。

> **警告**

通过`libcgroup`软件包提供的`cgconfig`工具可以挂载和处理控制器的层次结构，但不被`systemd`所支持（尤其是`net-prio`控制器）。绝对不要使用`libcgroup`工具来修改通过`systemd`所挂载的默认层次结构，因为这样会导致不可预知的错误。`libcgroup`软件包将在未来的Red Hat Enterprise Linux版本中移除。

### Systemd单元类型

> `systemd`是Red Hat Enterprise Linux 7开始取代`init`的服务管理系统，本段落内容适用于RHEL 7。

所有运行在系统（RHEL 7）中的进程都是`systemd` init进程的子进程。`systemd`提供了三种单元类型用于资源控制目的：

* `Service`服务 - 一个进程或者一组进程，由`systemd`基于单元(unit)配置文件启动。服务包装了特定的进程，这样它们可以作为一个整体进行启动或停止。服务被命名成如下方式：

```bash
name.service
```

* `Scope`范围 - 一组外部创建的进程。scope包装了通过`fork()`功能启动和停止的进程，然后在运行时由`systemd`注册进程。例如，用户会话，容器和虚拟机就被视为`scope`。scope被命名成如下方式：

```bash
name.scope
```

* `slice`分片 - 使用unit层次化组织的组。`slice`不包含进程，它是由`scope`和`service`组成的层次结构。活跃的进程则包含在scope或service中。在层次结构树中，每个`slice`单元的命名都对应了层级结构中指向目标的路径。符号`-`就表示路径组件特征。例如，如果一个slice类似如下：

```bash
parent-name.slice
```

则表示这个`parent-name.slice`是`parent.slice`的`subslice`，这个`slice`也可以有自己的`subslice`，例如`parent-name-name2.slice`，依次类推。这里的根`slice`是`-.slice`。

`service`，`scope`和`slice`单元在cgroup树中直接被映射到对象。当这些单元被激活，每个单元都各自直接映射到单元名字对应的cgroup路径。例如位于`test-waldo.slice`中的`ex.service`被映射到cgroup的`test.slice/test-waldo.slice/ex.service/`。

`service`，`scope`和`slice`可以由系统管理员手工创建或者由程序动态创建。默认情况，操作系统定义了一组运行系统所必须的服务。即，默认有4个`slice`：

* `-.slice` - 根`slice`
* `system.slice` - 所有系统服务的默认存放位置
* `user.slice` - 所有用户会话的默认存放位置
* `machine.slice` - 所有虚拟机和容器的默认存放位置

注意，所有用户会话被自动放到一个独立的scope单元，虚拟机和容器进程也是这样处理的。而且，所有用户被指派到一个默认的subslice。在这个默认配置中，系统管理员可以定义一个新的slice并指定service和scope到这个slice中。

以下是`systemd-cgls`命令的输出案例：

```bash
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
├─user.slice
│ └─user-1000.slice
│   └─session-2.scope
│     ├─2069 sshd: vagrant [priv]
│     ├─2072 sshd: vagrant@pts/0
│     ├─2073 -bash
│     ├─2253 systemd-cgls
│     └─2254 systemd-cgls
└─system.slice
  ├─postfix.service
  │ ├─1200 /usr/libexec/postfix/master -w
  │ ├─1216 qmgr -l -t unix -u
  │ └─2250 pickup -l -t unix -u
  ├─sshd.service
  │ └─888 /usr/sbin/sshd -D
  ...
```

上述案例可以看到`service`和`scope`包含进程，并且`service`和`scope`又被包含在`slice`中，而`slice`是不直接包含进程的。唯一的例外是`PID`为`1`的进程，位于特殊的`systemd.slice`中。还要注意，`-.slice`并没有显示在输出中，这是因为它表示了整个cgroup树。

`service`和`slice`单元可以通过单元文件配置或者动态通过调用`PID 1`的API来创建。`scope`单元则只能使用单元配置文件的方法来创建。通过API调用方法动态创建的单元是临时的并且只在运行期间存在。这些短暂存在的单元在单元结束时、禁用时或系统重启时自动释放。

## Linux内核中的资源控制器

资源控制器（resource controller），也称为cgroup子系统（cgroup subsystem），相当于一个单一资源，例如CPU时间或内存。Linux内核提供了一系列的资源控制器，它们都通过`systemd`自动挂载。

在`/proc/cgroups`中列出了当前挂载的resource controller列表

```bash
cat /proc/cgroups
```

输出内容

```bash
#subsys_name    hierarchy    num_cgroups    enabled
cpuset    7    1    1
cpu    5    1    1
cpuacct    5    1    1
memory    8    1    1
devices    10    1    1
freezer    6    1    1
net_cls    3    1    1
blkio    2    1    1
perf_event    4    1    1
hugetlb    9    1    1
```

也可以通过`lssubsys`(该命令属于`libcgroup-tools`软件包)，其中`-i`参数表示层次结构，`-m`参数表示输出挂载

```bash
lssubsys -i
```

输出

```bash
cpuset 7
cpu,cpuacct 5
memory 8
devices 10
freezer 6
net_cls 3
blkio 2
perf_event 4
hugetlb 9
```

```bash
lssubsys -m
```

```bash
cpuset /sys/fs/cgroup/cpuset
cpu,cpuacct /sys/fs/cgroup/cpu,cpuacct
memory /sys/fs/cgroup/memory
devices /sys/fs/cgroup/devices
freezer /sys/fs/cgroup/freezer
net_cls /sys/fs/cgroup/net_cls
blkio /sys/fs/cgroup/blkio
perf_event /sys/fs/cgroup/perf_event
hugetlb /sys/fs/cgroup/hugetlb
```

在RHEL 7中可用的资源控制器：

* `blkio` - 设置访问块设备的`I/O`存取限制
* `cpu` - 设置CPU调度算法提供cgroup调度任务访问CPU。这个挂载是和`cpuacct`控制器同时挂载的
* `cpuacct` - 通过使用cgroup的任务创建CPU资源的自动报告。这个挂载是和`cpu`控制器同时挂载的
* `cpuset` - 在多核系统中指定独立的CPU和内存节点给cgroup的任务
* `devices` - 允许或拒绝cgroup中的任务访问设备
* `freezer` - 挂起或继续cgroup重大任务
* `memory` - 通过cgroup中的任务设置内存限制，并通过其他任务来自动创建内存资源的报告
* `net_cls` - 通过分类标记（classid）来标记网络数据包，这样Linux流量控制器（`tc`命令）从参与的cgroup任务中标记数据包。
* `perf_event` - 通过`perf`工具激活监控cgroups
* `hugetlb` - 允许使用大的虚拟内存也，并强化资源限制在这些内存页

Linux内核针对可以通过`systemd`配置的资源控制来提供广泛的性能调优参数。

## 相关信息资源

### cgroup相关的systemd文档

以下手册页（man）包含了`systemd`下的cgroup通用信息

* `systemd.resource-control` - 描述通过system单元共享的资源控制配置选项
* `systemd.unit` - 描述所有单元配置文件的常用项
* `systemd.slice` - 提供`.slice`单元的通用信息
* `systemd.scope` - 提供`.scope`单元的通用信息
* `systemd.service` - 提供`.service`单元的通用信息

### 控制器相关内核文档

内核文档软件包提供了详细的有关所有资源控制器的文档。这个软件包包含了可选的订阅通道。

```bash
yum install kernel-doc
```

安装完成后，相关文件位于 `/usr/share/doc/kernel-doc-<kernel_version>/Documentation/cgroups/`目录。

### 在线文档

* [Red Hat Enterprise Linux 7 System Administrators Guide](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/index.html) - 详细解释了systemd概念和相关的服务管理方法
* [The D-Bus API of systemd](https://www.freedesktop.org/wiki/Software/systemd/dbus/) - 有关使用D-Bus API命令和`systemd`交互的参考手册

## 参考

* [INTRODUCTION TO CONTROL GROUPS (CGROUPS)](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Resource_Management_Guide/chap-Introduction_to_Control_Groups.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/os/linux/kernel/cgroups/rhel7/introduction.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
