Linux Cgroups 提供了对一组进程及将来子进程的资源限制、控制和统计的能力,这些资源包括 CPU、内存、存储、网络等。通过 Cgroups,可以方便地限制某个进程的资源占用,并且可以实时地监控进程的监控和统计信息。

Cgoups 中的 3 个组件

cproup

cgroup 是对进程分组管理的一种机制,一个 cgroup 包含一组进程,并可以在这个 cgroup 上增加 Linux subsystem 的各种参数配置,将一组进程和一组 subsystem 的系统参数关联起来。

subsystem

subsystem 是一组资源控制的模块,一般包含如下几项:

  • cpu 设置 cgroup 中进程的 CPU 被调度的策略。
  • devices 控制 cgroup 中进程对设备的访问。
  • freezer 用于挂起和恢复 cgroup 中的进程。
  • memory 用于控制 cgroup 中进程的内存占用。

每个 subsystem 会关联到定义了相应限制的 cgroup 上,并对这个 cgroup 中的进程做相应的限制和控制。

hierarchy

hierarchy 的功能是把一组 cgroup 串成一个树状的结构,一个这样的树便是一个 hierarchy,通过这种树状结构,Cgroups 可以做到继承。

三个组件相互的关系

  • 系统在创建了新的 hierarchy 之后,系统中所有的进程都会加入这个 hierarchy 的 cgroup 根节点,这个 cgroup 根节点是 hierarchy 默认创建的。
  • 一个 subsystem 只能附加到一个 hierarchy 上面。
  • 一个 hierarchy 可以附加多个 subsystem。
  • 一个进程可以作为多个 cgroup 的成员,但是这些 cgroup 必须在不同的 hierarchy 中。
  • 一个进程 fork 出子进程时,子进程是和父进程在同一个 cgroup 中的,也可以根据需要将其移动到其他 cgroup 中。

怎么调用 Kernel 才能配置 Cgroups 呢?

Kernel 为了使对 Cgroups 的配置更直观,是通过一个虚拟的树状文件系统配置 Cgroups 的,通过层级的目录虚拟 cgroup 树。

如何操作 Cgroups?

  1. 首先,创建并挂载一个 hierarchy(cgroup 树)
    1. 挂载后系统会在这个目录生成一些默认文件,如 task 文件,task 标识该 cgroup 下面的进程 ID,如果把一个进程 ID 写到 tasks 文件中,便会将相应的进程加入到这个 cgroup 中。
  2. 然后,在刚刚创建好的 hierarchy 上的 cgroup 根节点中扩展出新的 cgroup。
    1. 在一个 cgroup 的目录下创建文件夹时,Kernel 会把文件夹标记为这个 cgroup 的子 cgroup,它们会继承父 cgroup 的属性。
  3. 在 cgroup 中添加和移动进程。
    1. 一个进程在一个 Cgroups 的 hierarchy 中,只能在一个 cgroup 节点上存在,系统的所有进程都会默认在根节点上存在,可以将进程移动到其他 cgroup 节点,只需要将进程 ID 写到移动到的 cgroup 节点的 tasks 文件中即可。
  4. 通过 subsystem 限制 cgroup 中进程的资源。
    1. 其实系统默认已经为每个 subsystem 创建了一个默认的 hierarchy,比如 memory 的 hierarchy。我们可以通过在 memory 的 hierarchy 中创建 cgroup,限制进程占用的内存。

Docker 是如何使用 Cgroups 的?

Docker 通过为每个容器创建 cgroup,并通过 cgroup 去配置资源限制和资源监控。