cgroup v2架构演进与核心机制
cgroup(Control Group)是Linux内核提供的资源隔离与限制机制,是容器技术的底层基石。cgroup v2自Linux 4.5引入,相比v1最大的架构变化是统一的层级树(Unified Hierarchy),所有控制器挂载在同一棵cgroup树上,消除了v1中多控制器多层级导致的配置混乱与资源统计不一致问题。
cgroup v2的核心文件系统挂载在/sys/fs/cgroup,通过文件操作控制资源分配。每个cgroup目录包含cgroup.type、cgroup.procs、cgroup.controllers等通用文件,以及各控制器专属文件如cpu.max、memory.max。子cgroup默认继承父cgroup的控制器配置,可通过cgroup.subtree_control选择性启用。
v2的线程模式也做了统一:v1的cpu和cpuacct是独立控制器,v2合并为cpu控制器,通过cpu.stat提供统一的CPU统计。memory控制器同样合并了v1的memory和memsw,memory.max控制物理内存上限,memory.swap.max控制Swap使用量。
CPU资源隔离与带宽限制配置
cgroup v2的CPU控制器提供两种限制方式:cpu.weight(相对权重)和cpu.max(绝对上限)。
cpu.weight用于竞争场景下的CPU时间分配比例,取值1-10000,默认100。当系统CPU不紧张时,各cgroup可自由使用空闲CPU;资源争抢时按weight比例分配。此机制适合多租户环境的服务质量分级。
cpu.max设定硬上限,格式为配额周期,单位微秒。配额字段表示在一个周期内该cgroup最多使用的CPU时间:
# 限制该cgroup最多使用1.5个CPU核心
echo "150000 100000" > /sys/fs/cgroup/myapp/cpu.max
# 150000/100000 = 1.5,刓1.5核上限
# 查看配置
cat /sys/fs/cgroup/myapp/cpu.max
# 输出: 150000 100000
对多核系统,如需限制为2核,echo “200000 100000″。配额字段填max表示不限制。PERIOD默认100000微秒(100ms),通常不需要修改。
容器运行时(containerd、crun)通过cgroup v2实现CPU限制:
# Kubernetes Pod规格限制CPU
# requests: 500m (0.5核) limits: 2000m (2核)
# 对应cgroup v2: cpu.max = "200000 100000"
# cpu.weight基于requests计算
cpu.stat查看实际CPU消耗与限流统计:
cat /sys/fs/cgroup/myapp/cpu.stat
# usage_usec 523400000 # 累计使用CPU时间(微秒)
# user_usec 412300000 # 用户态时间
# system_usec 111100000 # 内核态时间
# nr_periods 5234 # 经历的周期数
# nr_throttled 12 # 被限流的周期数
# throttled_usec 3400000 # 累计限流时间(微秒)
nr_throttled持续增长说明CPU上限设置过低,应用频繁被限流,需适当上调。
内存限制与OOM Killer行为控制
memory.max设置物理内存硬上限,memory.high设置软上限触发回收,memory.swap.max控制Swap配额:
# 限制物理内存4GB,Swap允许1GB
echo "4294967296" > /sys/fs/cgroup/myapp/memory.max
echo "1073741824" > /sys/fs/cgroup/myapp/memory.swap.max
# 软上限3.5GB,超出后内核积极回收但不杀进程
echo "3758096384" > /sys/fs/cgroup/myapp/memory.high
cat /sys/fs/cgroup/myapp/memory.max
# 输出: 4294967296
OOM Killer行为通过memory.oom.group控制。设为1时,cgroup内任意进程触发OOM将整组杀掉;设为0时仅杀触发OOM的单个进程。对于Java应用,整组杀掉更合理,避免JVM部分线程被杀后进入不一致状态。
memory.events监控内存压力事件:
cat /sys/fs/cgroup/myapp/memory.events
# low 0 # 低于memory.low的次数
# high 23 # 超出memory.high的次数
# max 0 # 触发memory.max的次数
# oom 0 # OOM Killer触发的次数
# oom_kill 0 # 被OOM杀掉的进程数
high事件频繁触发说明应用常驻内存接近上限,需调查内存泄漏或调整配额。
IO带宽限制与混合工作负载隔离
cgroup v2的IO控制器支持按设备限制读写带宽和IOPS:
# 限制sda设备读取带宽10MB/s,写入50MB/s
echo "8:0 rbps=104857600 wbps=52428800" > /sys/fs/cgroup/myapp/io.max
# 限制IOPS: 读5000/s 写2000/s
echo "8:0 riops=5000 wiops=2000" > /sys/fs/cgroup/myapp/io.max
cat /sys/fs/cgroup/myapp/io.max
# 8:0 rbps=104857600 wbps=52428800 riops=5000 wiops=2000
8:0是设备号(major:minor),通过lsblk或cat /proc/partitions查看。IO限制对混合部署场景尤为重要——数据库的随机IO与日志服务的顺序IO争抢同一磁盘时,通过IO隔离确保数据库延迟不受日志写入影响。
cgroup v2故障排查与性能调优
常见问题与排查路径:
1. 容器CPU被限流:检查cpu.stat的nr_throttled,若持续增长且应用延迟抖动,适当提高cpu.max。Kubernetes中limits.cpu至少设为requests的2倍。
2. 内存OOM频繁:查看memory.events的oom计数,确认memory.current是否持续逼近memory.max。启用memory.high作为缓冲,比硬限制先触发回收。
3. IO瓶颈:io.stat显示await高但io.max未配额满,说明是底层设备瓶颈而非cgroup限制,需扩容存储或优化IO模式。
cgroup v2与systemd深度集成,系统服务可直接在Unit文件中配置资源限制:
# /etc/systemd/system/myapp.service
[Service]
MemoryMax=4G
MemoryHigh=3500M
CPUQuota=200%
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M
systemd会自动创建对应cgroup并写入配置,无需手动操作/sys/fs/cgroup文件。生产环境推荐通过systemd管理,避免手动cgroup操作导致配置丢失或与systemd冲突。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-nei-he-cgroupv2-zi-yuan-ge-li-yu-rong-qi-cpu-nei-cun/