Linux内核cgroup v2资源隔离配置与故障排查实战

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/

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

相关推荐