Linux cgroups(Control Groups)v2是内核提供的资源限制与隔离机制,在服务器运维和IDC数据中心环境中,cgroups v2能精确控制进程组的CPU、内存、IO等硬件资源配额,防止单个服务耗尽系统资源导致其他服务不可用。本文讲解cgroups v2的统一层级架构与实际配置方法。
cgroups v2统一层级架构与挂载配置
cgroups v2相比v1采用统一层级结构,所有资源控制器挂载在同一棵cgroup树中,避免了v1中各控制器独立层级的复杂管理。检查系统是否支持cgroups v2:
# 检查cgroups v2挂载状态
mount | grep cgroup2
# 输出示例
# cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
# 查看可用控制器
cat /sys/fs/cgroup/cgroup.controllers
# 输出: cpu io memory pids rdma
# 如果未挂载cgroups v2,手动挂载
mount -t cgroup2 none /sys/fs/cgroup
# 启用子控制器(在根cgroup中)
echo "+cpu +memory +io +pids" | tee /sys/fs/cgroup/cgroup.subtree_control
统一层级架构下,子cgroup自动继承父cgroup的限制策略。通过向cgroup.subtree_control文件写入控制器名称即可启用对应控制器,子目录中的进程受该控制器管辖。
CPU资源配额限制与权重分配
cgroups v2的CPU控制器通过cpu.max和cpu.weight两个文件实现配额限制。cpu.max设置绝对上限,cpu.weight设置相对权重。
# 创建服务cgroup目录
mkdir -p /sys/fs/cgroup/web_service
# 设置CPU配额:上限为2核(200000us per 100000us period)
echo "200000 100000" > /sys/fs/cgroup/web_service/cpu.max
# 设置CPU权重(范围1-10000,默认100)
# 权重10000的进程在争抢CPU时获得10倍于权重100的进程的时间片
echo "500" > /sys/fs/cgroup/web_service/cpu.weight
# 将进程PID写入cgroup
echo 12345 > /sys/fs/cgroup/web_service/cgroup.procs
# 验证CPU限制效果
# 启动CPU密集型进程
stress-ng --cpu 4 --timeout 30s &
# 监控CPU使用率
top -p $(cat /sys/fs/cgroup/web_service/cgroup.procs)
cpu.max格式为”$MAX $PERIOD”,表示在PERIOD微秒周期内最多使用MAX微秒CPU时间。设为”max”表示不限制。cpu.weight仅在CPU资源争抢时生效,CPU空闲时进程可使用全部资源。
内存限制与OOM控制策略
cgroups v2内存控制器通过memory.max设置硬上限,memory.high设置软上限,memory.swap.max设置swap使用上限。
# 设置内存硬上限为2GB
echo "2147483648" > /sys/fs/cgroup/web_service/memory.max
# 设置内存软上限为1.5GB(超过后内核开始回收该cgroup内存)
echo "1610612736" > /sys/fs/cgroup/web_service/memory.high
# 限制swap使用为512MB
echo "536870912" > /sys/fs/cgroup/web_service/memory.swap.max
# OOM控制:达到内存上限时杀死进程而非暂停
# 默认行为是OOM Kill,可通过memory.oom.group控制是否杀死整个cgroup
echo "1" > /sys/fs/cgroup/web_service/memory.oom.group
# 查看当前内存使用情况
cat /sys/fs/cgroup/web_service/memory.current
cat /sys/fs/cgroup/web_service/memory.max
cat /sys/fs/cgroup/web_service/memory.swap.current
memory.max设为”max”表示不限制内存。当cgroup内进程总内存达到memory.max时触发OOM Killer。memory.oom.group设为1时,内核会杀死该cgroup内所有进程,而非仅杀死占用内存最大的进程,适用于需要原子性失败的服务组。
IO带宽限制与设备级流量控制
IO控制器限制进程对块设备的读写带宽,通过io.max文件配置,格式为设备号:带宽限制。
# 获取块设备号
# 假设/dev/sda1的设备号为 8:1
lsblk -o NAME,MAJ:MIN
# 限制读写带宽:读100MB/s,写50MB/s
echo "8:1 rbps=104857600 wbps=52428800" > /sys/fs/cgroup/web_service/io.max
# 设置IO权重(范围1-10000,默认100)
echo "200" > /sys/fs/cgroup/web_service/io.weight
# 验证IO限制
# 执行IO密集型操作
dd if=/dev/zero of=/tmp/test_file bs=1M count=1024 oflag=direct
# 观察写入速度应被限制在50MB/s以内
# 查看IO使用统计
cat /sys/fs/cgroup/web_service/io.stat
# 输出示例:
# 8:1 rbytes=104857600 wbytes=52428800 rios=256 wios=128
io.max支持rbps(读字节/秒)、wbps(写字节/秒)、riops(读IOPS)、wiops(写IOPS)四个维度限制。设备号格式为”主设备号:次设备号”,可通过lsblk或stat命令获取。
systemd集成cgroups v2服务管理
在生产环境中,通过systemd管理服务资源限制更为方便,systemd原生支持cgroups v2,通过单元文件配置资源限制。
# /etc/systemd/system/webapp.service
[Unit]
Description=Web Application Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/webapp/app.py
Restart=always
# CPU限制:2核
CPUQuota=200%
# 内存限制:2GB
MemoryMax=2G
MemoryHigh=1536M
# IO限制:读100MB/s,写50MB/s
IOReadBandwidthMax=/dev/sda1 100M
IOWriteBandwidthMax=/dev/sda1 50M
# 进程数限制
TasksMax=100
# 限制swap使用
MemorySwapMax=512M
[Install]
WantedBy=multi-user.target
# 应用配置
systemctl daemon-reload
systemctl start webapp.service
# 查看资源使用统计
systemd-cgls
systemctl status webapp.service
systemctl show webapp.service -p CPUUsageNSec -p MemoryCurrent -p TasksCurrent
systemd的资源限制配置会自动转换为cgroups v2的对应文件写入。CPUQuota=200%等同于cpu.max设为”200000 100000″。使用systemd-cgtop命令可实时监控各服务的资源使用情况。
cgroups v2与v1兼容性及迁移注意事项
部分旧版软件和容器运行时仍依赖cgroups v1。通过内核参数可在v1和v2之间切换,但生产环境切换前需充分测试。
# 检查内核cgroups v2支持
grep cgroup /boot/config-$(uname -r)
# 应包含 CONFIG_CGROUPS=y 和 CONFIG_CGROUP_V2=y
# GRUB中启用cgroups v2(禁用v1)
# 编辑 /etc/default/grub
# 添加: GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
# 更新GRUB并重启
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
# 验证切换结果
stat -fc %T /sys/fs/cgroup
# 输出 cgroup2fs 表示v2,tmpfs 表示v1
# Docker使用cgroups v2
# Docker 20.10+原生支持cgroups v2
docker info | grep "Cgroup Version"
# 输出: Cgroup Version: 2
迁移到cgroups v2后,容器运行时(Docker、containerd)需要对应版本支持。Docker 20.10+和Kubernetes 1.25+均已提供cgroups v2支持。迁移过程中注意检查监控工具是否兼容v2的统计文件路径变化,Prometheus cgroups exporter等工具需要更新采集配置。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linuxcgroupsv2-zi-yuan-xian-zhi-shi-zhan-cpu-nei-cun-io-pei/