cgroups(Control Groups)是Linux内核提供的资源限制机制,cgroups v2采用统一层级架构替代v1的多控制器独立挂载,简化了资源配置逻辑。Docker、containerd等容器运行时底层均依赖cgroups实现CPU、内存、IO等资源隔离。本文从cgroups v2架构、资源控制器配置、容器场景实践三个层面展开。
cgroups v2统一层级架构与控制器配置
cgroups v2将所有控制器挂载到/sys/fs/cgroup单一层级下,通过cgroup.controllers文件声明子节点启用的控制器。每个cgroup目录包含cgroup.subtree_control(控制子节点启用哪些控制器)和各控制器的具体限制文件。
# 确认cgroups v2已启用
mount | grep cgroup
# 输出: cgroup2 on /sys/fs/cgroup type cgroup2 ...
# 查看根cgroup可用控制器
cat /sys/fs/cgroup/cgroup.controllers
# 输出: cpu cpuset io memory pids rdma hugetlb
# 创建资源限制组
mkdir -p /sys/fs/cgroup/app_limit
# 在子cgroup中启用控制器
echo "+cpu +memory +io +pids" > /sys/fs/cgroup/cgroup.subtree_control
# 写入资源限制
# CPU配额:200ms/100ms周期 = 2核
echo "200000 100000" > /sys/fs/cgroup/app_limit/cpu.max
# 内存上限:2GB
echo "2147483648" > /sys/fs/cgroup/app_limit/memory.max
# 进程数上限:500
echo "500" > /sys/fs/cgroup/app_limit/pids.max
# IO写入限速:每秒最多100MB
echo "8:0 rbps=104857600 wbps=104857600" > /sys/fs/cgroup/app_limit/io.max
cpu.max格式为”$MAX $PERIOD”,权重在cpu.weight中设置(1-10000,默认100)。memory.max设置硬限制,超出后触发OOM Killer。memory.high设置软限制,超过后内核回收页面但不禁用进程。
CPU资源隔离与调度权重配置
cgroups v2的CPU控制器提供两种限制模式:cpu.max绝对配额和cpu.weight相对权重。两者可叠加使用,配额决定上限,权重决定争抢比例。
# 方案A:绝对配额限制
echo "150000 100000" > /sys/fs/cgroup/app_limit/cpu.max
# 方案B:相对权重争抢
echo "256" > /sys/fs/cgroup/app_limit/cpu.weight
# 两个组权重256:128 = 2:1比例分配空闲CPU
# 方案C:CPU亲和性绑定
echo "0-3" > /sys/fs/cgroup/app_limit/cpuset.cpus
echo "0" > /sys/fs/cgroup/app_limit/cpuset.mems
# 将进程加入cgroup
echo $(pidof nginx) > /sys/fs/cgroup/app_limit/cgroup.procs
内存限制与OOM行为控制
memory.max触发硬OOM,memory.high触发内存回收。通过memory.oom.group可控制OOM时是否杀死整个cgroup内的所有进程,而非仅杀死占用最高的进程。
# 内存限制配置
echo "4294967296" > /sys/fs/cgroup/app_limit/memory.max
echo "3221225472" > /sys/fs/cgroup/app_limit/memory.high
echo "1" > /sys/fs/cgroup/app_limit/memory.oom.group
# Swap限制
echo "1073741824" > /sys/fs/cgroup/app_limit/memory.swap.max
# 查看内存使用统计
cat /sys/fs/cgroup/app_limit/memory.current
cat /sys/fs/cgroup/app_limit/memory.peak
cat /sys/fs/cgroup/app_limit/memory.events
# 输出示例: low 0 high 0 max 1 oom 1 oom_kill 2
Docker与containerd底层cgroups映射
Docker在cgroups v2环境下生成容器cgroup路径为/sys/fs/cgroup/system.slice/docker-<[container_id]>.scope。理解这层映射对排查容器资源泄漏问题至关重要。
# Docker资源限制参数对应cgroups配置
docker run -d \n --name webapp \n --cpus="2.0" \n --cpu-shares="512" \n --memory="4g" \n --memory-swap="5g" \n --pids-limit="500" \n --device-read-bps="/dev/sda:100mb" \n nginx:latest
# 查看容器实际cgroup路径
docker inspect --format='{{.HostConfig.CgroupParent}}' webapp
# 查看容器资源使用
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect -f '{{.Id}}' webapp | cut -c1-64).scope/memory.current
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect -f '{{.Id}}' webapp | cut -c1-64).scope/cpu.stat
资源压力监控与告警
memory.events文件记录内存压力事件计数,是判断资源瓶颈的关键依据。配合systemd-cgtop或自定义脚本可实现实时告警。
# systemd-cgtop实时查看各cgroup资源使用
systemd-cgtop
# 自定义监控脚本
#!/bin/bash
CGROUP_PATH="/sys/fs/cgroup/app_limit"
while true; do
MEM_CURRENT=$(cat $CGROUP_PATH/memory.current)
MEM_MAX=$(cat $CGROUP_PATH/memory.max)
UTIL=$((MEM_CURRENT * 100 / MEM_MAX))
if [ $UTIL -gt 80 ]; then
logger -t cgroup_monitor "WARNING: memory utilization ${UTIL}%"
fi
sleep 30
done
# PSI压力信息
cat /sys/fs/cgroup/app_limit/memory.pressure
# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0
PSI(Pressure Stall Information)提供some(部分任务阻塞)和full(所有任务阻塞)两档压力指标,total值持续增长说明资源不足,需上调限制或优化进程内存使用。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linuxcgroupsv2-zi-yuan-xian-zhi-pei-zhi-yu-rong-qi-zi-yuan/