什么是Cgroup @

根据维基百科的介绍

cgroups (abbreviated from control groups) is a Linux kernel feature that limits, accounts for, and isolates the resource usage of a collection of processes.

cgroups是linux内核提供的一项能力,用来控制某一个进程组的资源(IO、内存、CPU等)使用能力,这项功能的好处就是便于用户自己针对某个进程组分配资源。

cgroups也是docker的核心能力之一,目前cgroup主要分为两个版本,V1和V2,目前最新的内核都已经采用V2版本。V1由于规划较乱,实现版本较早,不易维护等问题会渐渐被V2版本完全取代。

cgruops可以理解为将进程组织为一棵棵树,每棵树用来限制一组资源,而树的节点就是一组进程,例如下图所示:

image

Subsystem: 可以理解为资源控制的模块,当它被一颗cgroup树关联后,就可以控制该树所有进程的资源,目前为止Linux 支持 12 种 subsystem。

hierarchy​: 可以理解为一棵 cgroup 树,树的每个节点就是一组进程,其可以被多个Subsystem关联,用来控制多种资源。

在cgroupV2版本,所有 Subsystem 使用统一的单层次树形结构,并且每个进程只能属于一个 cgroup,与V1版本对比的优点是更简洁、更一致、更容易管理。

cGroups文件系统 @

Cgroup通过VFS 文件系统将功能暴露给用户, 只需要通过写文件即可进行cgruop配置

VFS 是一个内核抽象层,能够隐藏具体文件系统的实现细节,从而给用户态进程提供一套统一的 API 接口。VFS 使用了一种通用文件系统的设计,具体的文件系统只要实现了 VFS 的设计接口,就能够注册到 VFS 中,从而使内核可以读写这种文件系统

# 进入cgroup文件目录
cd /sys/fs/cgroup

image

这是 Linux 的 cgroup (控制组) 文件系统 挂载点,用于资源管理和隔离,该目录下所有文件的用途和功能如下表。

cgroup核心控制文件

文件名 功能描述
cgroup.controllers 显示内核支持的、可用的资源控制器(如 cpu, memory, io 等)
cgroup.subtree_control 设置在下级子 cgroup 中启用的控制器
cgroup.procs 显示当前 cgroup 中包含的所有进程 ID (PID)
cgroup.threads 显示当前 cgroup 中包含的所有线程 ID (TID)
cgroup.stat 显示当前 cgroup 的基本状态信息
cgroup.pressure 显示当前 cgroup 的 CPU、内存和 I/O 压力状态
cgroup.max.depth 限制从当前 cgroup 开始的最大嵌套深度
cgroup.max.descendants 限制从当前 cgroup 开始的最大子 cgroup 数量

CPU 资源管理

文件名 功能描述
cpu.stat 显示 CPU 使用时间的详细统计(如用户态、系统态时间)
cpu.stat.local 显示当前 cgroup 本地的 CPU 使用统计
cpu.pressure 显示 CPU 资源压力的指标,反映任务等待 CPU 调度的情况
cpuset.cpus.effective 显示当前 cgroup 实际可用的 CPU 核心列表
cpuset.cpus.isolated 显示系统中被隔离(通常不用于普通任务)的 CPU 核心
cpuset.mems.effective 显示当前 cgroup 实际可用的内存节点(NUMA)列表

内存资源管理

文件名 功能描述
memory.stat 显示内存使用的极其详细的统计(缓存、RSS、交换区等)
memory.pressure 显示内存资源压力的指标,反映内存回收和紧张状况
memory.numa_stat 按 NUMA 节点显示内存统计信息
memory.reclaim 可手动写入以触发当前 cgroup 的内存回收
memory.zswap.writeback 显示从 zswap(压缩回写缓存)回写到交换区的数据量统计

I/O 资源管理

文件名 功能描述
io.stat 显示每个块设备的 I/O 操作量(读取/写入的字节数、次数)
io.pressure 显示 I/O 资源压力的指标,反映任务等待 I/O 完成的情况
io.prio.class 用于设置 cgroup 的 I/O 调度优先级类别
io.cost.model 用于配置 I/O 成本模型参数,以便进行权重控制
io.cost.qos 用于配置 I/O 服务质量参数,以控制带宽分配

系统服务与进程分组

文件名/目录名 功能描述
system.slice 包含所有系统服务(如 systemd 管理的服务)的 cgroup
user.slice 包含所有用户登录会话和相关进程的 cgroup
init.scope 包含系统初始化进程(如 systemd)的 cgroup

其他资源与挂载点

文件名 功能描述
irq.pressure 显示中断(IRQ)处理压力的指标
misc.capacity​ / misc.current 显示杂项资源的容量和当前使用量
dmem.capacity​ / dmem.current 显示设备内存的容量和当前使用量
*.mount 各种内核和特殊文件系统的挂载点(如大页内存、消息队列、调试跟踪等)

如何使用cgroup能力 @

通过将 cgroup 层级系统与 systemd 单位树捆绑,可以把资源管理设置从进程级别移至应用程序级别。

默认情况下,systemd 会自动创建 slice​、scope​ 和 service 单位的层级来为 cgroup 树提供统一结构。

所有资源默认会被划分为 3 个cgroup​: System​, User​ 和 Machine

每一个 cgroup​都是一个 slice​,每个slice​ 都可以有自己的子slice​,每个子 slice​ 都用 User ID​ 来命名,可以通过 systemctl 命令进行配置。

  • system.slice —— 所有系统 service 的默认位置
  • user.slice —— 所有用户会话的默认位置。每个用户会话都会在该 slice 下面创建一个子 slice,如果同一个用户多次登录该系统,仍然会使用相同的子 slice。
  • machine.slice —— 所有虚拟机和 Linux 容器的默认位置
# 通过下面命令查看systemctl配置cgruop的命令文档
systemctl set-property -h

# 可以在/run/systemd/system/ 下面查看创建出来的文件

# 通过下面命令查看cgroup的层级结构(静态信息快照)
systemd-cgls --no-page

# 查看cgroup层级的动态信息
systemd-cgtop 

docker-compose如何配置cgruop @

docker-compose.yml​ 文件中,你可以在服务定义下的 deploy.resources.limits 部分为服务设置资源限制。

version: '3.8'  # 使用 3.8 或更高版本以支持 `deploy` 配置
services:
  your_service:
    image: your_image:latest
    deploy:
      resources:
        limits:
          cpus: '0.50'   # 限制容器最多使用 0.5 个 CPU 核心
          memory: 512M   # 限制容器最多使用 512MB 内存
        reservations:
          cpus: '0.25'   # 容器启动时保留 0.25 个 CPU 核心
          memory: 256M   # 容器启动时保留 256MB 内存

配置项

  • cpus:指定容器可以使用的 CPU 核心数,可以是小数。
  • memory​:指定容器可以使用的内存大小,单位可以是 B​ (字节)、K​、M​、G)。
  • reservations​:指定资源预留值,确保容器至少能获得的资源量。

注意事项

  1. 版本兼容性:确保你使用的 Docker Compose 文件版本和 Docker Engine 版本支持上述配置选项。
  2. cgroup v2 支持:现在许多较新的 Linux 发行版默认使用 cgroup v2。Docker 20.10 及更高版本对 cgroup v2 有很好的支持。你可以通过检查 /sys/fs/cgroup/cgroup.controllers 文件是否存在来确认系统是否使用 cgroup v2
  3. 资源限制的生效​:通过 Compose 文件设置的资源限制主要是在容器运行时,由 Docker 通过对应的 cgroup 控制器(如 cpu​、memory)来强制执行。

参考链接 @