Cgroup 是什么?

一、基本概念

Cgroup(Control Groups)是 Linux 内核的一个功能,用于限制、记录和隔离进程组的资源使用。

简单理解:

  • Cgroup = Control Groups = 控制组
  • 作用:限制和管理进程的资源使用
  • 位置:Linux 内核功能,通过 /sys/fs/cgroup 文件系统访问

二、Cgroup 的作用

Cgroup 可以限制和管理:

资源类型 可以限制什么 实际例子
CPU CPU 使用率、CPU 时间片 限制容器最多使用 50% CPU
Memory 内存使用量、Swap 限制容器最多使用 512MB 内存
Block IO 磁盘读写速度 限制容器磁盘 IO 为 10MB/s
Network 网络带宽 限制容器网络带宽为 100Mbps
Process 进程数量 限制容器最多 100 个进程
Device 设备访问权限 允许/禁止访问特定设备

三、Cgroup 的工作原理

1. 文件系统接口

Cgroup 通过虚拟文件系统暴露:

/sys/fs/cgroup/

├── cpu/          # CPU 控制器

│   ├── docker/   # Docker 容器的 cgroup

│   └── ...

├── memory/       # 内存控制器

│   ├── docker/

│   └── ...

├── blkio/        # 块 IO 控制器

│   └── ...

└── pids/         # 进程数控制器

    └── ...

2. 层次结构

Cgroup 是树形结构:

/sys/fs/cgroup/cpu/

├── docker/                    # Docker 的父 cgroup

│   ├── <container-id-1>/     # 容器 1 的 cgroup

│   │   ├── cpu.cfs_quota_us  # CPU 配额

│   │   └── tasks             # 属于这个组的进程

│   └── <container-id-2>/     # 容器 2 的 cgroup

└── system.slice/              # systemd 服务的 cgroup

root@LAPTOP-LU4HDAFV:/sys/fs/cgroup# tree -L 1
.
├── cgroup.controllers
├── cgroup.max.depth
├── cgroup.max.descendants
├── cgroup.pressure
├── cgroup.procs
├── cgroup.stat
├── cgroup.subtree_control
├── cgroup.threads
├── cpu.pressure
├── cpu.stat
├── cpu.stat.local
├── cpuset.cpus.effective
├── cpuset.mems.effective
├── dev-hugepages.mount
├── dev-mqueue.mount
├── init.scope
├── io.pressure
├── io.stat
├── memory.numa_stat
├── memory.pressure
├── memory.reclaim
├── memory.stat
├── sys-fs-fuse-connections.mount
├── sys-kernel-config.mount
├── sys-kernel-debug.mount
├── sys-kernel-tracing.mount
├── system.slice
└── user.slice

10 directories, 19 files
root@LAPTOP-LU4HDAFV:/sys/fs/cgroup# 

=== cgroup.controllers 文件说明 ===

这个文件列出了系统可用的 Cgroup 资源控制器

=== 各个控制器的含义 ===

1. cpuset - CPU 核心和内存节点分配
2. cpu - CPU 使用限制和调度
3. io - 块设备 IO 限制
4. memory - 内存使用限制
5. hugetlb - 大页内存管理
6. pids - 进程数量限制
7. rdma - RDMA 资源限制

二、各分类详细说明

1. Cgroup 核心文件(8 个)- 管理 Cgroup 本身

作用:管理 Cgroup 系统本身,不直接限制资源

类比:公司总部的组织架构管理

文件 作用 类比
cgroup.controllers 列出有哪些控制器可用 公司有哪些部门
cgroup.procs 记录哪些进程在这个组 哪些员工在这个部门
cgroup.subtree_control 控制子组能用哪些控制器 子部门能用哪些工具
cgroup.max.depth 限制 Cgroup 树的深度 部门层级最多几层
cgroup.stat Cgroup 统计信息 部门统计报表

关键点:这些文件管理“谁在哪个组”,不直接限制资源。

2. CPU 控制器文件(3 个)- 控制 CPU 资源

作用:限制和管理 CPU 使用

类比:CPU 部门的规则和统计

文件 作用 实际内容
cpu.stat 记录 CPU 用了多少时间 usage_usec 5624888000(用了 5624 秒)
cpu.pressure 告诉你 CPU 是否紧张 CPU 压力信息
cpu.stat.local 本地 CPU 统计 本地 CPU 使用情况

关键点:这些文件限制和统计 CPU 使用,类似“电表”。

3. CPUset 控制器文件(2 个)- 控制 CPU 核心分配

作用:决定进程能用哪些 CPU 核心

类比:分配座位

文件 作用 实际内容
cpuset.cpus.effective 实际能用的 CPU 核心 0-11(能用所有 12 个核心)
cpuset.mems.effective 实际能用的内存节点 内存节点编号

关键点:这些文件限制“能用哪些 CPU 核心”,不是限制“用多少 CPU”。

4. IO 控制器文件(2 个)- 控制磁盘 IO

作用:限制和管理磁盘读写

类比:限速标志和流量统计

文件 作用 实际内容
io.stat 记录磁盘读写了多少 rbytes=2492019712(读了 2.3GB)
io.pressure 告诉你磁盘是否繁忙 IO 压力信息

关键点:这些文件限制和统计磁盘 IO,类似“限速标志”。

5. 内存控制器文件(4 个)- 控制内存资源

作用:限制和管理内存使用

类比:水表和限流阀

文件 作用 实际内容
memory.stat 记录内存用了多少 anon 1314009088(匿名页用了 1.2GB)
memory.pressure 告诉你内存是否紧张 内存压力信息
memory.reclaim 可以手动回收内存 内存回收接口
memory.numa_stat NUMA 内存统计 NUMA 节点内存使用

关键点:这些文件限制和统计内存使用,类似“水表”。

6. Cgroup 组目录(9 个)- 实际的 Cgroup 组

作用:实际的 Cgroup 组,包含进程和资源限制

类比:实际的部门

目录 类型 包含什么
system.slice/ slice 所有 systemd 系统服务
docker-<id>.scope/ scope Docker 容器的进程
init.scope/ scope init 进程(PID 1)
*.mount/ mount 各种挂载点的进程

关键点:

  • 目录 = 实际的组,里面有进程
  • 目录里也有控制文件(cpu.max、memory.current 等)
  • 这些文件控制目录里的进程

三、关键区别

文件 vs 目录
类型 是什么 作用 例子
文件 工具/规则 设置限制、查看统计 cpu.max, memory.current
目录 部门/组织 包含进程和资源限制 system.slice/, docker-<id>.scope/
根目录 vs 子目录

/sys/fs/cgroup/                    # 根目录

├── cpu.stat                       # 整个系统的 CPU 统计

├── memory.stat                    # 整个系统的内存统计

└── system.slice/                  # 子目录

    ├── cpu.stat                   # system.slice 的 CPU 统计

    ├── memory.stat                # system.slice 的内存统计

    │

    └── docker-<id>.scope/         # 子子目录

        ├── cpu.stat               # 容器的 CPU 统计

        └── memory.stat             # 容器的内存统计

四、实际例子

例子 1:查看整个系统的 CPU 使用

cat /sys/fs/cgroup/cpu.stat

# 输出: usage_usec 5624888000  (整个系统用了 5624 秒 CPU)

例子 2:查看容器的 CPU 使用

cat /sys/fs/cgroup/system.slice/docker-<id>.scope/cpu.stat

# 输出: usage_usec 134142  (这个容器用了 0.13 秒 CPU)

例子 3:限制容器的 CPU

# 写入限制到容器的 cpu.max 文件

echo "50000 100000" > /sys/fs/cgroup/system.slice/docker-<id>.scope/cpu.max

cpu.max 文件格式

格式:<quota> <period>

含义 CPU 使用率
max 100000 无限制 100%
100000 100000 限制 100% 100%
50000 100000 限制 50% 50%
25000 100000 限制 25% 25%

说明:

  • period(周期):通常是 100000 微秒 = 100ms
  • quota(配额):在这个周期内可以使用的时间(微秒)
  • CPU 使用率 = quota / period

五、总结

各分类的含义:

  1. Cgroup 核心文件 = 管理员
  • 管理“谁在哪个组”,不直接限制资源
  1. CPU/内存/IO 控制器文件 = 资源管理员
  • 限制和统计资源使用(CPU、内存、IO)
  1. Cgroup 组目录 = 实际的部门
  • 包含进程和资源限制
  • 目录里也有控制文件

关系:

  • 文件 = 工具(用来设置限制)
  • 目录 = 组织(包含进程和限制)
  • 目录里的文件 = 控制目录里的进程

这就是这些分类的含义。

Cgroup 可以设置的所有资源限制

除了 CPU 使用时间,Cgroup 还可以设置以下限制:

一、所有可设置的资源限制

1. CPU 相关限制(4 种)
文件 作用 设置示例
cpu.max CPU 使用时间限制 echo "50000 100000" > cpu.max (50% CPU)
cpu.weight CPU 权重(公平调度) echo "100" > cpu.weight (默认权重)
cpu.idle CPU 空闲时间 echo "0" > cpu.idle (禁用空闲)
cpu.max.burst CPU 突发限制 echo "10000" > cpu.max.burst
2. 内存相关限制(5 种)
文件 作用 设置示例
memory.max 最大内存使用量 echo "536870912" > memory.max (512MB)
memory.high 内存警告阈值 echo "268435456" > memory.high (256MB)
memory.low 内存保护阈值 echo "134217728" > memory.low (128MB)
memory.swap.max Swap 限制 echo "268435456" > memory.swap.max (256MB)
memory.min 最小内存保证 echo "67108864" > memory.min (64MB)
3. IO 限制(1 种)
文件 作用 设置示例
io.max 磁盘读写速度限制 echo "8:48 rbps=10485760 wbps=10485760" > io.max (10MB/s)
4. 进程数限制(1 种)
文件 作用 设置示例
pids.max 最大进程数 echo "100" > pids.max
5. CPU 核心分配(2 种)
文件 作用 设置示例
cpuset.cpus 指定可用的 CPU 核心 echo "0-3" > cpuset.cpus (只用 CPU 0-3)
cpuset.mems 指定可用的内存节点 echo "0" > cpuset.mems (只用内存节点 0)

二、实际设置示例

示例 1:限制 CPU 为 50%

echo "50000 100000" > /sys/fs/cgroup/system.slice/docker-<id>.scope/cpu.max

# 含义: 限制使用 50% CPU

示例 2:限制内存为 512MB

echo "536870912" > /sys/fs/cgroup/system.slice/docker-<id>.scope/memory.max

# 536870912 = 512 * 1024 * 1024 (字节)

示例 3:限制进程数为 100

echo "100" > /sys/fs/cgroup/system.slice/docker-<id>.scope/pids.max

示例 4:限制只能使用 CPU 0-3

echo "0-3" > /sys/fs/cgroup/system.slice/docker-<id>.scope/cpuset.cpus

示例 5:限制磁盘读写速度为 10MB/s

# 先找到设备号

lsblk

# 假设设备是 8:48

echo "8:48 rbps=10485760 wbps=10485760" > /sys/fs/cgroup/system.slice/docker-<id>.scope/io.max

# 10485760 = 10 * 1024 * 1024 (10MB/s)

示例 6:设置内存警告阈值

echo "268435456" > /sys/fs/cgroup/system.slice/docker-<id>.scope/memory.high

# 256MB,超过这个值会触发警告但不会杀死进程

示例 7:设置 CPU 权重

echo "200" > /sys/fs/cgroup/system.slice/docker-<id>.scope/cpu.weight

# 权重越高,CPU 分配越多(默认 100)

三、Docker 命令对应的 Cgroup 设置

Docker 命令 对应的 Cgroup 文件 设置的值
--cpus="0.5" cpu.max 50000 100000
--memory="512m" memory.max 536870912
--memory-swap="1g" memory.swap.max 1073741824
--pids-limit=100 pids.max 100
--cpuset-cpus="0-3" cpuset.cpus 0-3
--device-read-bps="/dev/sda:10mb" io.max 8:48 rbps=10485760
--device-write-bps="/dev/sda:10mb" io.max 8:48 wbps=10485760

四、完整的资源限制列表

Cgroup 可以设置的资源限制:

1. CPU 限制

   ✓ cpu.max          - CPU 使用时间(主要限制)

   ✓ cpu.weight       - CPU 权重(公平调度)

   ✓ cpu.idle         - CPU 空闲时间

   ✓ cpu.max.burst    - CPU 突发限制

2. 内存限制

   ✓ memory.max       - 最大内存(主要限制)

   ✓ memory.high      - 内存警告阈值

   ✓ memory.low       - 内存保护阈值

   ✓ memory.min       - 最小内存保证

   ✓ memory.swap.max  - Swap 限制

3. IO 限制

   ✓ io.max           - 磁盘读写速度(主要限制)

4. 进程数限制

   ✓ pids.max         - 最大进程数(主要限制)

5. CPU 核心分配

   ✓ cpuset.cpus      - 可用的 CPU 核心

   ✓ cpuset.mems      - 可用的内存节点

五、总结

除了设置 CPU 使用时间(cpu.max),Cgroup 还可以设置:

  1. CPU 权重(cpu.weight)- 公平调度
  1. 内存限制(memory.max)- 最大内存
  1. 内存阈值(memory.high/low)- 警告和保护
  1. Swap 限制(memory.swap.max)- Swap 使用
  1. IO 限制(io.max)- 磁盘读写速度
  1. 进程数限制(pids.max)- 最大进程数
  1. CPU 核心分配(cpuset.cpus)- 指定可用 CPU
  1. 内存节点分配(cpuset.mems)- 指定可用内存节点

这些限制共同控制容器的资源使用。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐