深入了解Linux命名空间的cgroups:打开容器技术的黑匣子
cgroups,全称为 Control Groups,是 Linux 内核提供的一种强大的资源管理机制。它的核心作用是将一组进程(tasks)组织成一个层级化的组,并为这些组分配、限制和监控资源的使用情况。 简单来说,cgroups 允许系统管理员(或容器运行时)对进程组的资源消耗进行精细化的控制,例如 CPU 使用率、内存占用、磁盘 I/O 以及网络带宽等。
可以将 cgroups 简单类比于“用户和组”的概念,但其作用范围扩展到了资源控制。 就像用户会继承其所在组的权限一样,进程会受到其所属 cgroup 的资源限制。
cgroups 的实现依赖于一系列的“子系统”(subsystems),每个子系统负责管理特定类型的资源。 常见的子系统包括:
-
cpu: 限制 CPU 使用率。
-
cpuacct: 统计 CPU 使用情况。
-
memory: 限制内存使用量。
-
blkio: 限制块设备(磁盘 I/O)的访问。
-
net_cls: 对网络数据包进行分类,配合
tc命令进行流量控制。 -
net_prio: 设置网络流量的优先级。
-
freezer: 冻结或恢复 cgroup 中的进程。
-
devices: 控制 cgroup 对设备的访问权限。
-
pids: 限制 cgroup 创建的进程数量。
这些子系统以层级结构的方式组织在一起,构成 cgroup 文件系统。 每个子系统对应 /sys/fs/cgroup 目录下的一个子目录。
可以使用 mount 命令来查看系统中已挂载的 cgroups 文件系统:
代码语言:Bash
自动换行
AI代码解释
mount -t cgroup
输出结果类似如下:
展开
代码语言:Bash
自动换行
AI代码解释
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids) cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
可以看到,每个子系统都挂载在 /sys/fs/cgroup 下的相应目录中。
或者,直接使用 ls 命令查看 /sys/fs/cgroup/ 目录的内容:
代码语言:Bash
自动换行
AI代码解释
ls /sys/fs/cgroup/
输出结果类似如下:
代码语言:Bash
自动换行
AI代码解释
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids rdma systemd
这些目录对应于不同的 cgroup 子系统。
在容器化技术中,cgroups 与 Linux 命名空间结合使用,为容器提供了一个隔离的资源环境。 命名空间负责隔离进程的文件系统、网络、用户等视图,而 cgroups 则负责限制容器的资源使用量。 通过这种方式,可以确保容器之间互不干扰,并且可以有效地利用系统资源。
二、CPU 子系统
CPU 子系统是 cgroups 中最重要的子系统之一,它控制 cgroup 中的进程可以使用的 CPU 资源。CPU 子系统通过两种主要的调度器来实现对 CPU 资源的分配和限制:
-
完全公平调度器 (CFS, Completely Fair Scheduler): 一种比例分配调度器,旨在公平地分配 CPU 时间给各个 cgroup。
-
实时调度器 (RT, Real-Time Scheduler): 用于管理实时任务的 CPU 使用,可以保证实时任务的响应时间。
2.1 完全公平调度器 (CFS)
CFS 是一种基于权重的调度器,它将 CPU 时间按比例分配给各个 cgroup。 CFS 使用以下关键参数进行配置:
-
cpu.cfs_period_us(周期): 定义 CFS 重新分配 CPU 资源的时间间隔,单位为微秒(µs)。 简单来说,它定义了 CPU 时间片分配的“周期”。 内核推荐的取值范围是 1000µs (1ms) 到 1000000µs (1s)。 较小的周期可以提供更精细的资源分配,但也会增加调度开销。 -
cpu.cfs_quota_us(配额): 定义在cpu.cfs_period_us周期内,一个 cgroup 中的所有任务可以运行的最大 CPU 时间,单位也是微秒(µs)。 可以将其理解为在一个周期内,cgroup 被允许使用的 CPU 时间的“配额”。 如果cpu.cfs_quota_us大于cpu.cfs_period_us,则表示该 cgroup 可以利用多个 CPU 核心。 例如,cpu.cfs_quota_us为 20000µs,cpu.cfs_period_us为 10000µs,则该 cgroup 最多可以使用 2 个 CPU 核心。 -
cpu.shares(份额): 使用一个整数来表示 cgroup 中任务可用的 CPU 时间的相对比例。cpu.shares的值不是绝对的 CPU 时间,而是相对于其他 cgroup 的权重。 例如,如果 cgroup A 的cpu.shares设置为 512,而 cgroup B 的cpu.shares设置为 1024,那么在 CPU 资源紧张的情况下,cgroup B 将获得 cgroup A 两倍的 CPU 时间。cpu.shares影响系统所有 CPU 的分配。 默认值为 1024。 -
cpu.stat(统计): 提供有关 CPU 时间使用情况的统计信息。 其中包含以下关键指标:-
nr_periods(周期数): 自 cgroup 创建以来,经过的cpu.cfs_period_us的周期数。 -
nr_throttled(节流次数): cgroup 中的任务由于超出cpu.cfs_quota_us限制而被限制运行的次数。 这个数字越高,说明 cgroup 的资源限制越频繁。 -
throttled_time(节流时间): cgroup 中的任务被限制运行的总时间,单位为纳秒 (ns)。 该值越高,说明 cgroup 受到资源限制的影响越大。
-
2.2 实时调度器 (RT)
RT 调度器用于管理实时任务的 CPU 使用,确保这些任务能够及时响应。 RT 调度器使用以下参数进行配置:
-
cpu.rt_period_us(RT 周期): 定义实时任务重新分配 CPU 资源的时间间隔,单位为微秒(µs)。 类似于 CFS 的cpu.cfs_period_us,但只对实时调度任务生效。 -
cpu.rt_runtime_us(RT 运行时): 指定在cpu.rt_period_us周期内,cgroup 中的实时任务可以连续访问 CPU 的最长时间,单位为微秒(µs)。 如果实时任务在cpu.rt_runtime_us时间内没有完成,则会被强制暂停,直到下一个周期开始。
以下是一些使用 CPU 子系统配置 cgroup 的示例。
示例 1: 使用 cpu.shares 分配 CPU 比例。假设有两个 cgroup,分别是 blue 和 red,我们希望 red cgroup 获得 blue cgroup 三倍的 CPU 时间。
代码语言:Bash
自动换行
AI代码解释
echo 250 > /sys/fs/cgroup/cpu/blue/cpu.shares echo 750 > /sys/fs/cgroup/cpu/red/cpu.shares
这将使 red cgroup 获得 blue cgroup 三倍的 CPU 时间。 注意,这里使用了 /sys/fs/cgroup/cpu 作为 cgroup 挂载点。
示例 2: 使用 cpu.cfs_quota_us 和 cpu.cfs_period_us 限制 cgroup 使用一个 CPU 核心。
代码语言:Bash
自动换行
AI代码解释
echo 100000 > /sys/fs/cgroup/cpu/red/cpu.cfs_quota_us echo 100000 > /sys/fs/cgroup/cpu/red/cpu.cfs_period_us
假设 cpu.cfs_period_us 设置为 100000µs (0.1 秒),并且 cpu.cfs_quota_us 也设置为 100000µs,这意味着 red cgroup 在每个 0.1 秒的周期内最多可以使用 0.1 秒的 CPU 时间,相当于完全使用一个 CPU 核心。
示例 3: 使用 cpu.cfs_quota_us 和 cpu.cfs_period_us 限制 cgroup 使用 10% 的 CPU 核心。
代码语言:Bash
自动换行
AI代码解释
echo 10000 > /sys/fs/cgroup/cpu/red/cpu.cfs_quota_us echo 100000 > /sys/fs/cgroup/cpu/red/cpu.cfs_period_us
在这个例子中,cpu.cfs_quota_us 为 10000µs,cpu.cfs_period_us 为 100000µs。 这意味着 red cgroup 在每个 0.1 秒的周期内最多可以使用 0.01 秒的 CPU 时间,相当于使用 10% 的 CPU 核心。
示例 4: 在多核系统中,允许 cgroup 使用两个 CPU 核心。
代码语言:Bash
自动换行
AI代码解释
echo 200000 > /sys/fs/cgroup/cpu/red/cpu.cfs_quota_us echo 100000 > /sys/fs/cgroup/cpu/red/cpu.cfs_period_us
在这种情况下,cpu.cfs_quota_us 是 cpu.cfs_period_us 的两倍。 这意味着 red cgroup 可以完全利用两个 CPU 核心。
注意: 配置 cgroups 需要 root 权限。 在使用 cgroups 之前,请确保您已经正确挂载了 cgroup 文件系统。 示例中的路径 /sys/fs/cgroup/cpu 可能会因系统配置而异。 您可以使用 mount -t cgroup 命令来查找正确的挂载点。
三、常用的子系统
3.1、cpuset 子系统
cpuset 子系统允许将特定的 CPU 和内存节点分配给 cgroup,从而实现更严格的资源隔离和 NUMA (Non-Uniform Memory Access) 优化。它为 cgroup 提供了独占或共享 CPU 和内存资源的能力。
-
cpuset.cpu_exclusive: 控制其他 cgroup (包括父 cgroup 和子 cgroup) 是否可以与该 cgroup 共享 CPU。-
0(默认): CPU 可以与其他 cpuset 共享。 -
1: CPU 专用于该 cpuset,其他 cpuset 无法使用。
-
-
cpuset.cpus(强制): 必须设置。指定 cgroup 中的任务可以访问的 CPU 列表。CPU 列表可以使用逗号分隔,也可以使用短划线表示范围。 例如,0-2,16表示允许使用 CPU 0、1、2 和 16。 -
cpuset.mem_exclusive: 控制其他 cpuset 是否可以与该 cgroup 共享内存节点。-
0(默认): 内存节点可以与其他 cpuset 共享。 -
1: 内存节点专用于该 cpuset,其他 cpuset 无法使用。 这与启用cpuset.mem_hardwall效果相同。
-
-
cpuset.mem_hardwall: 控制内存页和缓冲区在内核中的分配是否限制在指定的内存节点内。-
0(默认): 内存页和缓冲区可以在多个用户进程之间共享。 -
1: 启用 hardwall,每个任务的用户分配保持独立,可以提高安全性。
-
-
cpuset.memory_migrate: 控制在更改cpuset.mems的值时,是否将内存中的页迁移到新的内存节点。-
0(默认): 禁止内存迁移,页保留在原始分配的节点中。 -
1: 启用内存迁移,页迁移到新的cpuset.mems指定的内存节点。
-
-
cpuset.memory_pressure: 只读文件,包含该 cpuset 进程生成的“内存压力”的运行平均值。如果启用了cpuset.memory_pressure_enabled,则会自动更新该值。 -
cpuset.memory_pressure_enabled: 控制系统是否计算 cgroup 进程的“内存压力”。 内存压力代表进程尝试释放被占用的内存的速率。-
0(默认): 禁用内存压力计算。 -
1: 启用内存压力计算,并将结果输出到cpuset.memory_pressure。
-
-
cpuset.memory_spread_page: 控制文件系统缓冲是否应在该 cpuset 的内存节点中均匀分布。-
0(默认): 缓冲位于生成缓冲的进程所运行的同一节点中。 -
1: 文件系统缓冲在 cpuset 的内存节点中均匀分布。
-
-
cpuset.memory_spread_slab: 控制是否在 cpuset 之间平均分配用于文件 I/O 操作的内核高速缓存 slab。-
0(默认): 内核高速缓存 slab 不平均分配,位于生成它们的进程所运行的同一节点中。 -
1: 内核高速缓存 slab 在 cpuset 间平均分配。
-
-
cpuset.mems(强制): 必须设置。指定 cgroup 中的任务可以访问的内存节点列表。 与cpuset.cpus类似,可以使用逗号和短划线表示范围。 例如,0-2,16表示允许使用内存节点 0、1、2 和 16。 内存节点与 CPU 相关联,代表内存被划分成的物理区域。 -
cpuset.sched_load_balance: 控制内核是否在该 cpuset 的 CPU 中平衡负载。-
1(默认): 内核将超载 CPU 中的进程移动到负载较低的 CPU 中以平衡负载。 -
0: 禁用负载平衡。
-
cpuset.sched_relax_domain_level: 定义内核应尝试平衡负载的 CPU 宽度范围。 仅当启用 cpuset.sched_load_balance 时才有效。
更多推荐
所有评论(0)