Linux服务器环境中,Cgroup v2是内核提供的资源控制框架,用于限制和隔离进程组的CPU、内存、IO等资源。与Cgroup v1相比,v2采用统一层级(Unified Hierarchy)模型,所有控制器挂载在同一棵cgroup树下,资源控制更一致、更易管理。Docker、containerd、Kubernetes等容器运行时已全面支持Cgroup v2,服务器运维中掌握Cgroup v2配置对资源规划和故障排查至关重要。
Cgroup v2架构演进与统一层级模型
Cgroup v1为每个控制器(cpu、memory、blkio等)维护独立的cgroup层级,进程可同时存在于多个控制器的不同cgroup中,导致状态不一致和管理复杂。Cgroup v2将所有控制器统一到单一层级,进程在一个cgroup中的位置决定了其所有资源限制。
检查系统是否启用Cgroup v2:
# 检查cgroup v2挂载状态
mount | grep cgroup
# 输出应包含: cgroup2 on /sys/fs/cgroup type cgroup2
# 查看支持的控制器
cat /sys/fs/cgroup/cgroup.controllers
# 输出示例: cpuset cpu io memory hugetlb pids rdma
# 查看当前进程的cgroup
cat /proc/self/cgroup
# v2输出: 0::/some/path(单一层级)
# v1输出: 多行,每行一个控制器
systemd在Cgroup v2中扮演核心角色。systemd自动挂载cgroup2文件系统,并将每个systemd unit映射为一个cgroup。资源限制通过systemd unit配置文件或运行时命令设置,无需手动操作cgroup虚拟文件系统。
CPU资源限制与CPU控制器配置实战
Cgroup v2的CPU控制通过cpu.weight和cpu.max两个参数实现。cpu.weight定义相对权重(范围1-10000,默认100),用于在CPU资源争抢时按比例分配。cpu.max定义绝对限制,格式为$MAX $PERIOD,表示在每$PERIOD微秒周期内最多使用$MAX微秒CPU时间。
# 通过systemd限制服务CPU使用
# 编辑service的资源限制
systemctl set-property myapp.service CPUWeight=512 CPUQuota=200%
# CPUQuota=200% 表示最多使用2个CPU核心
# 对应 cgroup v2: cpu.max = 200000 100000
# 直接通过cgroup文件系统设置
# 创建子cgroup
mkdir /sys/fs/cgroup/myapp
# 启用CPU控制器
echo "+cpu" > /sys/fs/cgroup/cgroup.subtree_control
# 设置CPU权重(相对值,争抢时生效)
echo 512 > /sys/fs/cgroup/myapp/cpu.weight
# 设置CPU上限(绝对值,2核 = 200000/100000)
echo "200000 100000" > /sys/fs/cgroup/myapp/cpu.max
# 将进程加入cgroup
echo $PID > /sys/fs/cgroup/myapp/cgroup.procs
CPU权重机制适用于多服务共享CPU的场景。当3个服务权重分别为100、200、300,CPU空闲时各服务均可满载运行;CPU满载时,服务按1:2:3比例分配。这种设计比v1的cpu.shares语义更清晰,且支持嵌套层级继承。
内存限制与OOM行为控制
Cgroup v2内存控制支持细粒度限制,包括物理内存(memory.max)和内存+Swap总量(memory.swap.max)。当进程组内存使用超过限制时,内核触发OOM Killer终止组内进程。
# systemd内存限制
systemctl set-property myapp.service MemoryMax=4G MemorySwapMax=2G MemoryHigh=3G
# MemoryMax: 硬限制,超过触发OOM
# MemoryHigh: 软限制,超过后内核加速回收页面
# MemorySwapMax: Swap使用上限
# 直接cgroup操作
echo "+memory" > /sys/fs/cgroup/cgroup.subtree_control
mkdir /sys/fs/cgroup/myapp
echo 4294967296 > /sys/fs/cgroup/myapp/memory.max # 4GB
echo 2147483648 > /sys/fs/cgroup/myapp/memory.swap.max # 2GB
# 查看内存使用情况
cat /sys/fs/cgroup/myapp/memory.current
cat /sys/fs/cgroup/myapp/memory.peak
# 查看OOM事件
cat /sys/fs/cgroup/myapp/memory.events
# 输出示例:
# oom 3
# oom_kill 2
# oom_group_kill 1
memory.oom.group参数控制OOM行为。设为1时,cgroup内任一进程被OOM Killer选中,组内所有进程都会被终止。这在容器场景中符合预期——一个Pod内的容器应共存亡。
# 配置OOM组杀行为
echo 1 > /sys/fs/cgroup/myapp/memory.oom.group
# 自定义OOM处理:监听memory.events
# 使用inotify等待oom事件,触发优雅退出
inotifywait -e modify /sys/fs/cgroup/myapp/memory.events
磁盘IO与网络带宽限流配置
Cgroup v2的IO控制器通过io.max和io.weight限制块设备读写带宽。io.max格式为$MAJOR:$MINOR rbps=$B wbps=$B riops=$I wiops=$I,可分别限制读写速率和IOPS。
# 查看块设备major:minor
lsblk -o NAME,MAJ:MIN
# 限制服务IO带宽(sda通常为8:0)
systemctl set-property myapp.service IOReadBandwidthMax=/dev/sda 100M IOWriteBandwidthMax=/dev/sda 50M IOReadIOPSMax=/dev/sda 1000 IOWriteIOPSMax=/dev/sda 500
# 直接cgroup操作
echo "+io" > /sys/fs/cgroup/cgroup.subtree_control
mkdir /sys/fs/cgroup/myapp
# 限制sda读取100MB/s,写入50MB/s
echo "8:0 rbps=104857600 wbps=52428800" > /sys/fs/cgroup/myapp/io.max
网络带宽限流在Cgroup v2中不直接支持,需配合tc(Traffic Control)工具实现。常见方案是使用cgroup clsact将cgroup ID与tc filter绑定,或通过nftables的cgroup match模块按cgroup限流。
# 使用nftables按cgroup限制网络带宽
nft add table inet cgroup_filter
nft 'add chain inet cgroup_filter output { type filter hook output priority 0; }'
# 限制cgroup myapp的出站带宽为100Mbps
nft 'add rule inet cgroup_filter output cgroup "myapp" limit rate 100 mbytes/second accept'
# 对比tc方案(需ifb设备配合)
# 创建ifb虚拟设备
modprobe ifb numifbs=1
ip link set ifb0 up
# 将流量重定向到ifb0
tc qdisc add dev eth0 ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
# 在ifb0上设置htb限速
tc qdisc add dev ifb0 root handle 1: htb
tc class add dev ifb0 parent 1: classid 1:1 htb rate 100mbit
Cgroup v2在Linux 5.15+内核中已趋于稳定,主流发行版(Ubuntu 22.04+、RHEL 9+、Debian 12+)默认启用。在容器运维实践中,理解Cgroup v2的资源控制机制有助于精确规划算力资源分配、快速定位容器资源争抢问题,并为高可用集群的服务隔离提供底层支撑。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-cgroupv2-zi-yuan-xian-zhi-yu-rong-qi-ge-li/