Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Linux cgroups

一、cgroups 是什么?

cgroups = Linux 内核的「资源配额与控制系统」

如果说:

  • Namespace:你 能看到什么
  • cgroups:你 能用多少

那么 容器 = Namespace + cgroups

二、cgroups 能干什么?

资源 能控制什么
CPU 使用比例、上限、调度
Memory 最大内存、OOM 行为
I/O 磁盘读写限速
PIDs 最大进程数
Network 间接(通过 tc / BPF)
HugePages 巨页配额
Devices 设备访问

三、cgroups 的两个时代:v1 vs v2(非常关键)

1️⃣ cgroups v1(历史包袱)

  • 多层级、多 controller
  • 每个 controller 一棵树
  • 混乱、容易配置错
/sys/fs/cgroup/memory
/sys/fs/cgroup/cpu
/sys/fs/cgroup/blkio

2️⃣ cgroups v2(RHEL 9 / AlmaLinux 9 默认)

  • 单一层级
  • 统一接口
  • 更强的资源模型
/sys/fs/cgroup/
├── cgroup.controllers
├── cgroup.subtree_control
├── cpu.max
├── memory.max
├── io.max

📌 RHEL 8+ / Debian 11+ 推荐只用 v2

四、cgroups v2 的核心设计思想

1️⃣ 单一层级(Unified Hierarchy)

所有资源:

/sys/fs/cgroup/

2️⃣ Controller 必须显式开启

echo "+cpu +memory" > cgroup.subtree_control

3️⃣ 父组限制 = 子组上限

子组的资源不能超过父组

五、cgroups v2 的核心 Controller

☘️ CPU Controller

1️⃣ cpu.max(核心)

cpu.max = <quota> <period>
  • 100000 100000 = 1 core
  • 200000 100000 = 2 cores
  • max 100000 = 不限

2️⃣ cpu.weight(比例)

cpu.weight = 1 ~ 10000

📌 默认 100

☘️ Memory Controller(最重要)

1️⃣ memory.max(硬限制)

memory.max = 512M

超出:

  • OOM kill
  • 不影响宿主

2️⃣ memory.high(软限制)

memory.high = 400M
  • 超过 -> 回收 / throttling
  • 不直接 OOM

3️⃣ memory.swap.max

memory.swap.max = 0   # 禁用 swap

4️⃣ memory.current

实时使用量

💽 IO Controller(生产常用)

io.max="8:0 rbps=10M wbps=5M"

🔢 PIDs Controller(防 fork 炸弹)

pids.max = 256

🧩 Devices Controller(v2 有限制)

v2 不再推荐直接用 devices

-> eBPF / LSM

六、cgroups 是如何生效的?

1️⃣ cgroup 作用于进程

echo <pid> > cgroup.procs

2️⃣ 子进程自动继承

七、systemd 与 cgroups(非常重要)

1️⃣ systemd = cgroups 管理器

  • 每个 service / slice 都是 cgroup
  • systemd 只支持 v2(RHEL 9)

2️⃣ systemd cgroup 层级

/
├── system.slice
│   └── sshd.service
├── user.slice
│   └── user-1000.slice
└── machine.slice
    └── docker-xxx.scope

3️⃣ systemd 资源限制示例

[Service]
MemoryMax=1G
CPUQuota=200%
TasksMax=512

八、Docker / Podman / K8S 与 cgroups

Docker

docker run -m 512m --cpus=1 nginx

-> 转换为:

  • memory.max
  • cpu.max

Kubernetes

Pod 配置 cgroup 映射
limits.memory memory.max
requests.cpu cpu.weight

📌 requests ≠ limits

九、NUMA + cgroups(高级)

  • 默认不绑定 NUMA
  • 可结合:
    • cpuset.cpus
    • cpuset.mems
cpuset.cpus=0-7
cpuset.mems=0

📌 数据库强烈建议

十、OOM 行为与 memory.oom.group

memory.oom.group=1
  • 整个 cgroup 一起 kill
  • 防止“半死不活”

十一、监控与排查

1️⃣ 查看系统 cgroup 版本

stat -fc %T /sys/fs/cgroup
  • cgroup2fs -> v2

2️⃣ 查看进程所在 cgroup

cat /proc/<pid>/cgroup

3️⃣ 实时监控

cat memory.current
cat cpu.stat

十二、生产实践总结(非常重要)

推荐

  • 用 cgroups v2
  • 通过 systemd 管理
  • 设置 pids.max
  • 设置 memory.high + memory.max

雷区

  • v1/v2 混用
  • memory.max 不留余量
  • 忽略 swap 行为
  • 容器无限 fork

十三、Namespace vs cgroups 对照表

维度 Namespace cgroups
作用 隔离 限制
粒度 视图 配额
是否限制资源
容器必需

十四、总结

Namespace 决定世界的边界

cgroups 决定资源的上限