cgroup v2资源隔离的核心架构差异
cgroup v2相比v1最大的架构变化是采用统一层级(unified hierarchy),所有控制器挂载在同一棵cgroup树下,解决了v1中多层级导致的资源分配混乱问题。在Linux 5.x及以上内核中,cgroup v2已成为默认方案,主流发行版(Ubuntu 22.04+、CentOS 9+)均已默认启用。
验证当前系统cgroup版本的方法:
# 查看cgroup挂载信息
mount | grep cgroup
# 如果只看到cgroup2类型挂载,说明已使用v2
cgroup2 on /sys/fs/cgroup type cgroup2
# 查看内核支持的控制器
cat /sys/fs/cgroup/cgroup.controllers
# 输出示例: cpuset cpu io memory hugetlb pids rdma misc
CPU资源隔离配置实战
cgroup v2的CPU控制器通过cpu.max和cpu.weight两个核心文件控制资源分配。cpu.max设置硬上限,cpu.weight设置相对权重。
# 创建业务cgroup
mkdir -p /sys/fs/cgroup/app-backend
# 设置CPU硬上限:200000 100000表示每100ms周期内最多使用200ms
# 即限制为2个CPU核心
echo "200000 100000" > /sys/fs/cgroup/app-backend/cpu.max
# 设置相对权重(范围1-10000,默认100)
echo 200 > /sys/fs/cgroup/app-backend/cpu.weight
# 将进程加入cgroup
echo $PID > /sys/fs/cgroup/app-backend/cgroup.procs
对于CPU亲和性控制,需要配合cpuset控制器:
# 启用cpuset控制器
echo "+cpuset" > /sys/fs/cgroup/app-backend/cgroup.subtree_control
# 限制进程只能运行在CPU 0-3号核心
mkdir -p /sys/fs/cgroup/app-backend/db-service
echo "0-3" > /sys/fs/cgroup/app-backend/db-service/cpuset.cpus
echo "0-1" > /sys/fs/cgroup/app-backend/db-service/cpuset.mems
内存资源隔离与OOM防护
内存控制器是生产环境最常用的隔离手段,核心文件包括memory.max(硬上限)、memory.high(软上限)和memory.swap.max(swap限制)。
# 设置内存硬上限4GB
echo 4294967296 > /sys/fs/cgroup/app-backend/memory.max
# 设置软上限3.5GB,超过后内核施加回收压力但不杀进程
echo 3758096384 > /sys/fs/cgroup/app-backend/memory.high
# 禁用swap
echo 0 > /sys/fs/cgroup/app-backend/memory.swap.max
# 查看当前内存使用
cat /sys/fs/cgroup/app-backend/memory.current
cat /sys/fs/cgroup/app-backend/memory.peak # 历史峰值
关键区别:memory.high超过后进程会变慢但不会被杀;memory.max超过后触发OOM killer。生产环境建议先用memory.high做预警,观察一段时间后再设置memory.max。
IO带宽限制配置
IO控制器可以对块设备的读写带宽进行精细化限制,防止日志写入或批量导出等IO密集型任务影响数据库等延迟敏感服务。
# 启用IO控制器(需在父cgroup层面)
echo "+io" > /sys/fs/cgroup/cgroup.subtree_control
# 查看块设备主次设备号
lsblk -o NAME,MAJ:MIN
# 假设sda为8:0
# 设置IO带宽限制:读20MB/s 写10MB/s
echo "8:0 rbps=20971520 wbps=10485760 riops=0 wiops=0" > \
/sys/fs/cgroup/app-backend/io.max
# 查看IO统计
cat /sys/fs/cgroup/app-backend/io.stat
# 8:0 rbytes=12345678 wbytes=8765432 rios=567 wios=234
常见故障排查场景
场景一:进程被OOM kill但memory.current远低于memory.max。这通常是因为memory.kmem(内核内存)未被计入memory.current。排查方式:
# 检查内核内存使用
cat /sys/fs/cgroup/app-backend/memory.kmem.current
# 检查events文件中的OOM事件
cat /sys/fs/cgroup/app-backend/memory.events
# oom 3 # OOM触发次数
# oom_kill 1 # 进程被杀次数
场景二:cgroup中进程CPU使用率超过cpu.max设定值。原因可能是cpu.stat统计的是累计值,需关注当前周期内的实际消耗。另外,线程在cgroup之间迁移时,旧cgroup的配额占用不会立即释放。
# 查看CPU使用统计
cat /sys/fs/cgroup/app-backend/cpu.stat
# usage_usec 123456789
# user_usec 98765432
# system_usec 24691357
# nr_periods 4567
# nr_throttled 23 # 被限流次数
# throttled_usec 89012 # 被限流总时长
场景三:无法在子cgroup中设置资源限制,提示Permission denied或Operation not permitted。这通常是因为父cgroup未正确启用子控制器:
# 父cgroup必须通过subtree_control向下传递控制器
echo "+cpu +memory +io" > /sys/fs/cgroup/app-backend/cgroup.subtree_control
# 子cgroup创建后才能设置限制
mkdir /sys/fs/cgroup/app-backend/child
echo "200000 100000" > /sys/fs/cgroup/app-backend/child/cpu.max
cgroup v2与容器运行时的集成
containerd 1.6+和Docker 20.10+已原生支持cgroup v2。Kubernetes从1.25版本正式支持cgroup v2。在cgroup v2环境下,容器的资源限制通过统一的cgroup树传递,无需像v1那样在多个层级之间协调。
# Docker指定cgroup v2资源限制
docker run --cpus=2 --memory=4g --memory-swap=4g \
-d nginx:latest
# 对应的cgroup路径位于
# /sys/fs/cgroup/system.slice/docker-.scope/
在混合v1/v2环境中迁移时,需注意v2不支持v1的net_cls和net_prio控制器,网络带宽限制需改用tc命令或Cilium等eBPF方案实现。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-nei-he-cgroupv2-zi-yuan-ge-li-pei-zhi-yu-gu-zhang-pai/