Skip to content
60.Docker»30.Cgroups»LV001-Cgroups简介.md

LV001-Cgroups简介 ​

使用不同的 Namespace,可以实现容器中的进程看不到别的容器的资源,但是有一个问题,容器内的进程仍然可以任意地使用主机的 CPU 、内存等资源,如果某一个容器使用的主机资源过多,可能导致主机的资源竞争,进而影响业务。那如果我们想限制一个容器资源的使用(如 CPU、内存等)应该如何做呢?

一、Cgroups ​

1. 什么是 Cgroups ​

Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制(Limit),统计(Account),隔离(Isolate)进程组(process groups)所使用物理资源的机制。最初由 google 工程师提出,后来被整合进 Linux 的内核。因此,Cgroups 为容器实现虚拟化提供了基本保证,是构建 Docker, LXC 等一系列虚拟化管理工具的基石。

手撕Linux Cgroups —— Cgroups实战分析以及在Docker中的应用

在 2006 年,Google 的工程师( Rohit Seth 和 Paul Menage 为主要发起人) 发起了这个项目,起初项目名称并不是 cgroups,而被称为进程容器(process containers)。在 2007 年 cgroups 代码计划合入 Linux 内核,但是当时在 Linux 内核中,容器(container)这个词被广泛使用,并且拥有不同的含义。为了避免命名混乱和歧义,进程容器被重名为 cgroups,并在 2008 年成功合入 Linux 2.6.24 版本中。cgroups 目前已经成为 systemd、Docker、Linux Containers(LXC) 等技术的基础。

这里还有1份官方文档可以参考:Control Group v2 — The Linux Kernel documentation

2. 为什么容器需要 Cgroups ​

如果没有 Cgroup,所有容器运行在宿主机上时:

  • 容易出现某个容器独占 CPU;

  • 内存泄漏会导致宿主机 OOM;

  • I/O 密集型容器可能拖慢整个系统。

通过 Cgroup,Docker 能为每个容器设定“上限”,例如:

  • CPU 只能用 20%
  • 内存最多 512MB
  • 最多允许 100 个进程
  • 限制磁盘写入速率 10MB/s

这样,每个容器都像被分配了独立的资源配额,互不干扰。

3. 提供了哪些功能 ​

cgroups 主要提供了如下功能。

  • 资源限制: 限制资源的使用量,例如我们可以通过限制某个业务的内存上限,从而保护主机其他业务的安全运行。
  • 优先级控制:不同的组可以有不同的资源( CPU 、磁盘 IO 等)使用优先级。
  • 审计:计算控制组的资源使用情况。
  • 控制:控制进程的挂起或恢复。

二、基本概念 ​

1. task ​

task 就是系统的一个进程,在 Cgroups 中叫 task 而已。

2. 三个核心概念 ​

cgroups 功能的实现依赖于三个核心概念:子系统、控制组、层级树。

  • 子系统(subsystem):是一个内核的组件,一个子系统代表一类资源调度控制器。例如内存子系统可以限制内存的使用量,CPU 子系统可以限制 CPU 的使用时间。
  • 控制组(cgroup):表示一组进程和一组带有参数的子系统的关联关系。例如,一个进程使用了 CPU 子系统来限制 CPU 的使用时间,则这个进程和 CPU 子系统的关联关系称为控制组。
  • 层级树(hierarchy):是由一系列的控制组按照树状结构排列组成的。这种排列方式可以使得控制组拥有父子关系,子控制组默认拥有父控制组的属性,也就是子控制组会继承于父控制组。比如,系统中定义了一个控制组 c1,限制了 CPU 可以使用 1 核,然后另外一个控制组 c2 想实现既限制 CPU 使用 1 核,同时限制内存使用 2G,那么 c2 就可以直接继承 c1,无须重复定义 CPU 限制。

cgroups 的三个核心概念中,子系统是最核心的概念,因为子系统是真正实现某类资源的限制的基础。

3.1 subsystem ​

subsystem 就是一个资源调度控制器(Resource Controller)。比如 CPU 子系统可以控制 CPU 时间分配,内存子系统可以限制内存使用量。

每个 subsystem 背后都有相应的内核模块来配合它完成对资源的控制。比如对 cpu 资源的限制是通过进程调度模块根据 cpu 子系统的配置来完成的;对内存资源的限制则是内存模块根据 memory 子系统的配置来完成的,而对网络数据包的控制则需要 Traffic Control 子系统来配合完成。cgroups 为每种可以控制的资源定义了一个子系统。

典型的子系统介绍如下:

(1)cpu: 主要限制进程的 cpu 使用率。

(2)cpuacct: 可以统计 cgroups 中的进程的 cpu 使用报告。

(3)cpuset: 可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。

(4)memory: 可以限制进程的 memory 使用量。

(5)blkio: 可以限制进程的块设备 io。

(6)devices: 可以控制进程能够访问某些设备。

(7)net_cls: 可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。

(8)freezer: 可以挂起或者恢复 cgroups 中的进程。

3.2 cgroup ​

cgroup 是 Cgroups 中的资源控制的单位。cgroup 表示按照某种资源控制标准划分而成的任务组,可以包含一个或多个 subsystem。如果把一个 task 加入到一个 cgroup 中,那么这个 task 使用的资源将受到该 cgroup 中指定的标准限制。

cgroup 有两个版本:cgroup v1 和 cgroup v2。以下是判断系统当前使用的 cgroup 版本的几种方法:

shell
# 1. mount: 如果输出中包含多个以 cgroup 开头的挂载点(如 cpu、memory 等),则为 cgroup v1。如果输出中只有一个 cgroup2 挂载点,则为 cgroup v2。
mount | grep cgroup

# 2. /proc/cmdline, 如果输出包含 systemd.unified_cgroup_hierarchy = 1 或 unified_cgroup_hierarchy = 1,则为 cgroup v2。果没有该参数或值为 0,则为 cgroup v1。
cat /proc/cmdline

两个版本对比如下:

对比项 v1 v2
控制器结构 各自独立 统一管理
层级模型 控制器可挂载多次 单一树结构
文件接口 分散复杂 简洁一致
Docker 默认 旧版使用 v1 新版全面支持 v2

3.3 hierarchy ​

hierarchy 由一系列 cgroup 以一个树状结构排列而成,每个 hierarchy 通过绑定对应的 subsystem 进行资源调度。hierarchy 中的 cgroup 节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个 hierarchy。hierarchy 的树状结构在用户态的表现形态为文件系统的层级结构,用户操作 hierarchy 就像创建文件夹,修改文件一样。

就类似这样:

shell
cgroup
 ├── docker
 │    ├── container_1
 │    └── container_2
 └── system.slice

参考资料

(9 封私信) 手撕 Linux Cgroups —— Cgroups 实战分析以及在 Docker 中的应用 - 知乎

Docker 底层:cgroups 实现资源限制 - 拾月凄辰 - 博客园

管理容器的资源:深入理解 Cgroup 机制-CSDN 博客

莫道桑榆晚 为霞尚满天.