Linux cgroup v2资源限制配置与CPU内存隔离调优实战

Linux cgroup v2是内核级资源隔离的核心机制,在容器运行时、systemd服务管理、多租户云环境中广泛使用。相比cgroup v1,v2采用统一层级结构,引入PSI(Pressure Stall Information)监控,并在CPU和内存控制语义上做了重大改进。正确配置cgroup v2能有效防止单个进程耗尽系统资源导致雪崩。

cgroup v2与v1的核心差异

cgroup v1为每种资源类型维护独立的层级树(cpu、memory、blkio等),各子系统互不感知。v2将所有资源控制器挂在同一个层级下,一个cgroup目录同时管理CPU、内存、IO等多种资源。

关键架构变化:

– 统一层级:/sys/fs/cgroup/为根,所有子cgroup共享同一棵树
– 委派授权:子cgroup可由非root用户管理,通过写入cgroup.procs实现
– PSI指标:cpu.pressure、memory.pressure、io.pressure提供精确的资源压力量化
– 域内线程:cgroup.threads支持线程级控制(v1仅支持进程级)

检查系统是否已启用cgroup v2:

# 查看挂载类型
mount | grep cgroup
# 输出: cgroup2 on /sys/fs/cgroup type cgroup2

# 确认controllers
cat /sys/fs/cgroup/cgroup.controllers
# 输出: cpuset cpu io memory hugetlb pids rdma misc

CPU资源限制配置与CPU权重分配

cgroup v2提供两种CPU控制方式:权重(weight)和上限(max)。

权重模式用于相对分配,类似nice值但更精确:

# 创建服务cgroup
mkdir -p /sys/fs/cgroup/system.slice/myapp
# 设置CPU权重,默认100,范围1-10000
echo 256 > /sys/fs/cgroup/system.slice/myapp/cpu.weight

# 设置CPU硬上限:最多使用4个核
echo "400000 100000" > /sys/fs/cgroup/system.slice/myapp/cpu.max
# 格式: $MAX $PERIOD,表示每100000微秒周期内最多使用400000微秒CPU时间

cpu.max的格式为”MAX PERIOD”,MAX为微秒数。设为”max”则不限制。实际CPU使用率计算:MAX/PERIOD = 400000/100000 = 4核。

对于NUMA架构,可通过cpuset控制器绑定NUMA节点:

# 启用cpuset控制器
echo "+cpuset" > /sys/fs/cgroup/cgroup.subtree_control
# 绑定到NUMA节点0
echo 0 > /sys/fs/cgroup/system.slice/myapp/cpuset.mems
# 绑定CPU 0-3
echo 0-3 > /sys/fs/cgroup/system.slice/myapp/cpuset.cpus

内存限制与OOM控制策略

cgroup v2的内存控制合并了v1中分散的memory.limit_in_bytes和memsw.limit_in_bytes,通过memory.max和memory.swap.max统一管理:

# 设置内存硬限制为4GB
echo 4294967296 > /sys/fs/cgroup/system.slice/myapp/memory.max

# 设置swap限制为1GB(不设则默认无限制)
echo 1073741824 > /sys/fs/cgroup/system.slice/myapp/memory.swap.max

# 设置内存软限制,内核在内存压力时优先回收此cgroup
echo 2147483648 > /sys/fs/cgroup/system.slice/myapp/memory.low

四个关键内存指标的语义:

– memory.max:硬上限,超过触发OOM killer
– memory.high:软上限,超过后内核加速回收该cgroup内存
– memory.low:保护线,低于此值时内核不回收该cgroup内存
– memory.swap.max:swap使用上限

OOM行为可自定义控制:

# 默认行为:cgroup内进程被OOM kill
# 设置为1则cgroup内进程被冻结而非kill(配合 freezer 使用)
echo 1 > /sys/fs/cgroup/system.slice/myapp/memory.oom.group

当memory.oom.group=1时,OOM killer会一次性杀死该cgroup内所有进程,而非挑选单个进程。适用于一组紧密协作的进程,单个被杀后其余也无法正常运行。

IO带宽限制与blkio控制

cgroup v2的IO控制器直接控制块设备读写带宽:

# 启用io控制器
echo "+io" > /sys/fs/cgroup/cgroup.subtree_control

# 限制对sda的读写:最大100MB/s读、50MB/s写
# 格式: $MAJOR:$MINOR rbps=$VAL wbps=$VAL
echo "8:0 rbps=104857600 wbps=52428800" > /sys/fs/cgroup/system.slice/myapp/io.max

获取设备号:

stat -c '%t:%T' /dev/sda
# 输出: 8:0

IO权重分配:

echo 100 > /sys/fs/cgroup/system.slice/myapp/io.weight
# 默认权重100,范围1-10000

通过systemd管理cgroup v2配置

生产环境推荐通过systemd unit文件管理cgroup,而非手动操作sysfs:

# /etc/systemd/system/myapp.service
[Service]
ExecStart=/usr/bin/myapp
# CPU限制:最多4核
CPUQuota=400%
# 内存限制:最多4GB
MemoryMax=4G
# 内存软限制
MemoryHigh=3G
# Swap限制
MemorySwapMax=1G
# IO读写限制
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M
# CPU权重
CPUWeight=256
# 重启策略
Restart=on-failure
RestartSec=5
systemctl daemon-reload
systemctl start myapp

systemd自动将以上参数转换为cgroup v2文件写入对应路径。查看运行时状态:

systemctl status myapp
systemd-cgls
# 或查看具体资源使用
cat /sys/fs/cgroup/system.slice/myapp/memory.current
cat /sys/fs/cgroup/system.slice/myapp/cpu.stat

PSI压力监控与告警集成

PSI(Pressure Stall Information)是cgroup v2引入的资源压力量化指标,比传统load average更精确:

cat /sys/fs/cgroup/system.slice/myapp/cpu.pressure
# 输出: some avg10=2.50 avg60=1.20 avg300=0.80 total=12345678
#       full avg10=1.00 avg60=0.50 avg300=0.30 total=5678901

PSI指标含义:

– some:至少一个任务等待资源的时间占比
– full:所有任务都在等待资源的时间占比
– avg10/avg60/avg300:10秒、60秒、300秒滑动平均
– total:累计等待时间(微秒)

memory.pressure的full指标超过5%通常意味着严重的内存不足,需要扩容或调整限制。配合Prometheus采集可实现自动化告警。

cgroup v2资源隔离故障排查

常见问题排查:

1. 进程未受cgroup限制:检查进程是否在cgroup.procs列表中

cat /sys/fs/cgroup/system.slice/myapp/cgroup.procs
# 若进程不在其中,手动加入:
echo $PID > /sys/fs/cgroup/system.slice/myapp/cgroup.procs

2. OOM频繁触发但内存未超限:检查slab内核缓存占用

cat /sys/fs/cgroup/system.slice/myapp/memory.stat | grep slab
# kernel_stack、page_cache等内核内存也计入memory.current

3. CPU限制不生效:确认cpu.max格式正确,PERIOD不能为0

# 验证当前配置
cat /sys/fs/cgroup/system.slice/myapp/cpu.max
# 应输出类似: 400000 100000

4. 子cgroup无法创建:检查父cgroup的cgroup.subtree_control是否启用了对应controller

# 在父级启用
echo "+cpu +memory +io" > /sys/fs/cgroup/system.slice/cgroup.subtree_control

5. 嵌套容器场景:Docker和systemd争抢cgroup管理权,需要配置Docker使用systemd cgroup driver

# /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"]
}

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linuxcgroupv2-zi-yuan-xian-zhi-pei-zhi-yu-cpu-nei-cun-ge-li/

(0)
小编小编
上一篇 12小时前
下一篇 12小时前

相关推荐