cgroups(Control Groups)是Linux内核提供资源限制与隔离的核心机制,服务器运维中Docker、containerd等容器运行时均依赖cgroups实现CPU、内存、IO等资源管控。cgroups v2采用统一层级架构,相比v1的资源控制器分散设计,在配置管理和资源统计方面更为简洁。本文以实际服务器环境为背景,演示cgroups v2的资源限制配置与容器隔离实践。
cgroups v2架构与统一层级
cgroups v2最大的变化是统一层级(Unified Hierarchy)设计。v1中CPU、内存、IO等控制器各自挂载在独立的目录树下,配置分散且子层级关系混乱。v2将所有控制器挂载到同一个层级下,通过`cgroup.controllers`文件声明可用的控制器,子cgroup通过`cgroup.subtree_control`启用具体控制器。
检查系统cgroups版本:
# 查看cgroups v2是否启用
mount | grep cgroup
# 输出: cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec)
# 查看可用控制器
cat /sys/fs/cgroup/cgroup.controllers
# 输出: cpu cpuset io memory pids rdma
# 查看当前cgroup版本
stat -fc %T /sys/fs/cgroup
# 输出: cgroup2fs (v2) 或 tmpfs (v1)
各控制器的功能说明:
cpu - CPU时间片分配与带宽限制
cpuset - CPU核心亲和性绑定
io - 块设备IO带宽限制
memory - 内存使用量限制与OOM控制
pids - 进程数量限制
rdma - RDMA资源限制
CPU资源限制配置实战
cgroups v2的CPU控制通过`cpu.weight`和`cpu.max`两个文件实现。`cpu.weight`定义相对权重(范围1-10000,默认100),`cpu.max`定义绝对上限。
创建cgroup并限制CPU使用:
# 创建cgroup
mkdir /sys/fs/cgroup/myapp
# 启用CPU控制器
echo "+cpu" > /sys/fs/cgroup/cgroup.subtree_control
# 设置CPU权重(相对值,影响争抢时的分配比例)
echo 256 > /sys/fs/cgroup/myapp/cpu.weight
# 设置CPU绝对上限(格式: quota period)
# 以下配置等效于限制为1.5个CPU核心
echo "150000 100000" > /sys/fs/cgroup/myapp/cpu.max
# 将进程加入cgroup
echo $$ > /sys/fs/cgroup/myapp/cgroup.procs
验证CPU限制效果,运行一个消耗CPU的进程:
# 在受限cgroup中运行
dd if=/dev/zero of=/dev/null &
PID=$!
echo $PID > /sys/fs/cgroup/myapp/cgroup.procs
# 查看CPU使用率(应被限制在150%以内)
top -p $PID
多核CPU绑定通过cpuset控制器实现:
# 启用cpuset控制器
echo "+cpuset" > /sys/fs/cgroup/cgroup.subtree_control
# 绑定到CPU 2和CPU 3
echo "2-3" > /sys/fs/cgroup/myapp/cpuset.cpus
# 绑定NUMA节点
echo "0" > /sys/fs/cgroup/myapp/cpuset.mems
内存限制与OOM控制
cgroups v2的内存控制通过`memory.max`和`memory.high`配置。`memory.max`是硬限制,超出后触发OOM Killer;`memory.high`是软限制,超出后内核开始回收页面。
# 启用memory控制器
echo "+memory" > /sys/fs/cgroup/cgroup.subtree_control
# 设置硬限制为2GB
echo "2147483648" > /sys/fs/cgroup/myapp/memory.max
# 设置软限制为1.5GB(内核开始积极回收)
echo "1610612736" > /sys/fs/cgroup/myapp/memory.high
# 禁用OOM Killer(进程超额后进入等待而非被杀)
echo "1" > /sys/fs/cgroup/myapp/memory.oom.group
查看内存使用统计:
cat /sys/fs/cgroup/myapp/memory.current
cat /sys/fs/cgroup/myapp/memory.peak
# 输出字段说明:
# memory.current - 当前内存使用量(字节)
# memory.peak - 历史峰值内存使用量
# memory.swap.current - 当前Swap使用量
# memory.events - 内存事件计数(oom, oom_kill等)
查看内存事件计数:
cat /sys/fs/cgroup/myapp/memory.events
# 输出示例:
# low 42
# high 0
# max 0
# oom 1
# oom_kill 1
IO带宽限制配置
cgroups v2的IO控制通过`io.max`文件设置,格式为`MAJ:MIN rbps= wbps= riops= wiops=`。
# 查看块设备主次设备号
lsblk -o NAME,MAJ:MIN
# 输出: sda 8:0
# 启用io控制器
echo "+io" > /sys/fs/cgroup/cgroup.subtree_control
# 限制读速度100MB/s,写速度50MB/s
echo "8:0 rbps=104857600 wbps=52428800" > /sys/fs/cgroup/myapp/io.max
# 限制IOPS(每秒读写次数)
echo "8:0 riops=2000 wiops=1000" >> /sys/fs/cgroup/myapp/io.max
验证IO限制效果:
# 写入测试(受限于50MB/s)
dd if=/dev/zero of=/tmp/testfile bs=1M count=500 oflag=direct
# 观察写入速度应被限制在50MB/s左右
# 读取测试(受限于100MB/s)
dd if=/tmp/testfile of=/dev/null bs=1M iflag=direct
容器运行时的cgroups v2集成
Docker默认可能使用cgroups v1,需确认并切换到v2。在`/etc/docker/daemon.json`中配置:
{
"exec-opts": ["native.cgroupdriver=cgroupfs"],
"default-cgroupns-mode": "private"
}
确认Docker使用cgroups v2:
docker info | grep -i cgroup
# 输出: Cgroup Version: 2
运行容器时指定资源限制:
docker run -d --name myapp --cpus="1.5" --memory="2g" --memory-swap="2g" --device-read-bps="/dev/sda:100mb" --device-write-bps="/dev/sda:50mb" --pids-limit="200" nginx:latest
# 查看容器的cgroup路径
docker inspect myapp --format '{{.HostConfig.CgroupParent}}'
containerd的cgroups v2配置在`config.toml`中:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
systemd与cgroups v2协同
现代Linux发行版默认使用systemd管理cgroups,systemd提供了一套更高层的资源限制接口。创建服务单元文件时可直接声明资源限制:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
[Service]
ExecStart=/usr/bin/myapp
# CPU限制(相当于cpu.max)
CPUQuota=150%
# CPU权重(相当于cpu.weight)
CPUWeight=256
# 内存限制
MemoryMax=2G
MemoryHigh=1500M
# IO限制
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M
# 进程数限制
TasksMax=200
[Install]
WantedBy=multi-user.target
启动服务并验证资源限制:
systemctl daemon-reload
systemctl start myapp
# 查看服务的cgroup资源使用
systemd-cgtop -n 1 myapp.service
# 查看详细资源统计
systemctl show myapp.service -p CPUUsageNSec -p MemoryCurrent -p TasksCurrent
cgroups v2通过统一层级简化了资源管理配置。在服务器运维实践中,结合systemd或容器运行时的高层接口,可快速实现进程级别的CPU、内存、IO资源隔离。生产环境部署时需关注内存限制与OOM策略的配合,避免因OOM Kill导致服务中断。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linuxcgroupsv2-zi-yuan-xian-zhi-pei-zhi-yu-rong-qi-cpu-nei/