什么是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可以理解为将进程组织为一棵棵树,每棵树用来限制一组资源,而树的节点就是一组进程,例如下图所示:
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
这是 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:指定资源预留值,确保容器至少能获得的资源量。
注意事项
- 版本兼容性:确保你使用的 Docker Compose 文件版本和 Docker Engine 版本支持上述配置选项。
- cgroup v2 支持:现在许多较新的 Linux 发行版默认使用 cgroup v2。Docker 20.10 及更高版本对 cgroup v2 有很好的支持。你可以通过检查
/sys/fs/cgroup/cgroup.controllers文件是否存在来确认系统是否使用 cgroup v2 - 资源限制的生效:通过 Compose 文件设置的资源限制主要是在容器运行时,由 Docker 通过对应的 cgroup 控制器(如
cpu、memory)来强制执行。
参考链接 @