四、Linux 内核容器技术深度解析系列-8-linux-kernel-container-cgroups-part3-deep
·
Linux 内核容器技术:CGroups 资源限制核心技术(第二部分 - 深度优化)
第三部分:内核实现与高级优化
内核源码级解析
CGroups 核心数据结构
// include/linux/cgroup-defs.h - CGroups 核心结构
// 1. 控制组子系统状态
struct cgroup_subsys_state {
struct cgroup *cgroup; // 所属控制组
struct cgroup_subsys *ss; // 所属子系统
// 层级关系
struct cgroup_subsys_state *parent;
struct list_head children;
struct list_head sibling;
// 引用计数
atomic64_t refcnt;
// 在线状态
bool online;
};
// 2. 控制组对象
struct cgroup {
// 自旋锁保护
raw_spinlock_t lock;
// 引用计数
atomic64_t refcnt;
// 层级关系
struct cgroup *parent;
struct list_head children;
// 子系统状态
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
// 进程列表
struct cgroup_taskset tasks;
// 文件系统
struct kernfs_node *kn;
// 控制组 ID
u64 id;
// 控制标志
unsigned long flags;
};
// 3. CGroups 根节点
struct cgroup_root {
// 层级 ID
int hierarchy_id;
// 根节点
struct cgroup cgrp;
// 子系统掩码
u16 subsys_mask;
// 层级标志
unsigned long flags;
// 命名空间
struct cgroup_namespace *ns;
// 层级名称
char name[CGROUP_ROOT_NAME_MAX];
};
// 设计要点:
// 1. 树状结构:parent/children 形成层级
// 2. 子系统挂载:每个子系统通过 subsys 数组挂载
// 3. 引用计数:refcnt 管理生命周期
// 4. 锁保护:自旋锁保证并发安全
CPU 控制器实现
// kernel/sched/fair.c - CFS 调度器集成
// CPU 控制器配置
struct cfs_bandwidth {
raw_spinlock_t lock;
ktime_t period; // 周期时间 (纳秒)
s64 quota; // 配额时间 (纳秒)
s64 runtime; // 剩余运行时间
// 运行队列
struct list_head throttled_cfs_rq;
// 定时器
struct hrtimer period_timer;
};
// CFS 运行队列
struct cfs_rq {
struct load_weight load; // 负载权重
unsigned long nr_running; // 运行进程数
u64 min_vruntime; // 最小虚拟运行时间
// 红黑树 (按 vruntime 排序)
struct rb_root tasks_timeline;
struct rb_node *rb_leftmost;
// CGroups 支持
struct cgroup_subsys_state *tg;
struct cfs_bandwidth *cfs_bandwidth;
// 统计信息
u64 exec_clock;
u64 min_vruntime;
u64 runtime_expires;
};
// CPU 限制实现
static void __account_cfs_cpu_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
{
struct cfs_bandwidth *cfs_b = cfs_rq->cfs_bandwidth;
// 1. 扣除执行时间
cfs_b->runtime -= delta_exec;
// 2. 检查是否超限
if (cfs_b->runtime < 0) {
// 3. 限流处理
throttle_cfs_rq(cfs_rq);
}
}
// 限流机制
static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
{
struct cfs_bandwidth *cfs_b = cfs_rq->cfs_bandwidth;
// 1. 从运行队列移除
list_del(&cfs_rq->throttled_list);
list_add_tail(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
// 2. 禁用调度
cfs_rq->throttled = 1;
// 3. 唤醒定时器 (等待下个周期)
hrtimer_start(&cfs_b->period_timer,
cfs_b->period,
HRTIMER_MODE_REL);
}
// 性能优化:
// - 时间复杂度:O(1) 配额检查
// - 空间复杂度:O(N), N=控制组数量
// - 定时器精度:高精度定时器 (hrtimer)
内存控制器实现
// mm/memcontrol.c - 内存控制器
// 内存控制组
struct mem_cgroup {
// 子系统状态
struct cgroup_subsys_state css;
// 内存统计
struct page_counter memory;
struct page_counter memsw;
struct page_counter kmem;
// 内存阈值
unsigned long low;
unsigned long high;
unsigned long max;
// 内存回收
struct reclaim_state reclaim_state;
struct work_struct reclaim_work;
// 事件等待队列
wait_queue_head_t waitq;
// OOM 控制
struct oom_control oom;
// 每 CPU 统计
struct mem_cgroup_per_cpu *percpu;
};
// 内存限制检查
static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
unsigned int nr_pages)
{
// 1. 检查是否超过限制
if (page_counter_try_charge(&memcg->memory, nr_pages, &counter))
return 0; // 成功
// 2. 尝试内存回收
if (mem_cgroup_reclaim(memcg, gfp_mask, nr_pages))
return 0; // 回收成功
// 3. 检查是否允许超过
if (gfp_mask & __GFP_NOFAIL)
return 0; // 允许超过
// 4. 触发 OOM
mem_cgroup_oom(memcg, gfp_mask, nr_pages);
return -ENOMEM;
}
// OOM 处理
static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t gfp_mask,
int order)
{
// 1. 检查 OOM 是否禁用
if (memcg->oom_kill_disable) {
// 进程进入等待
wait_event_lock_irq(memcg->waitq,
!memcg->under_oom,
&memcg->oom_lock);
return;
}
// 2. 选择牺牲进程
struct task_struct *p = mem_cgroup_select_oom_victim(memcg);
// 3. 发送 SIGKILL
if (p) {
send_sig(SIGKILL, p, 0);
memcg->oom_kill_count++;
}
}
// 内存回收策略:
// 1. 扫描匿名页和文件页
// 2. 优先回收不活跃页
// 3. 使用 LRU 算法
// 4. 考虑页面优先级
I/O 控制器实现
// block/blk-cgroup.c - 块设备 I/O 控制器
// I/O 控制组
struct blkcg {
// 子系统状态
struct cgroup_subsys_state css;
// I/O 权重
unsigned int weight;
unsigned int leaf_weight;
// I/O 限制
struct blkg_policy_data pd[BLKCG_MAX_POLS];
// 统计信息
struct blkg_iostat_set iostat;
};
// I/O 限制策略
struct blkcg_policy {
int pol_id;
const char *name;
// 回调函数
int (*init_fn)(struct blkcg *blkcg);
void (*exit_fn)(struct blkcg *blkcg);
// 限制检查
bool (*allow_fn)(struct request_queue *q,
struct bio *bio,
struct blkcg *blkcg);
};
// I/O 限流实现 ( throttling )
static bool blk_throtl_bio(struct bio *bio)
{
struct blkcg *blkcg = bio_blkcg(bio);
struct throtl_grp *tg = blkg_to_tg(bio->bi_blkg);
// 1. 检查带宽限制
if (tg->bps_limit < U64_MAX) {
if (tg->bps_disp[READ] + bio->bi_iter.bi_size > tg->bps_limit) {
// 超过限制,加入等待队列
throtl_enqueue_bio(tg, bio);
return true;
}
}
// 2. 检查 IOPS 限制
if (tg->iops_limit[READ] < UINT_MAX) {
if (tg->iops_disp[READ] + 1 > tg->iops_limit[READ]) {
throtl_enqueue_bio(tg, bio);
return true;
}
}
return false;
}
// 令牌桶算法
static void tg_update_disp(struct throtl_grp *tg)
{
u64 now = ktime_get_ns();
u64 elapsed = now - tg->last_update;
// 补充令牌
tg->bytes_disp[READ] -=
(tg->bps_limit[READ] * elapsed) / NSEC_PER_SEC;
tg->iops_disp[READ] -=
(tg->iops_limit[READ] * elapsed) / NSEC_PER_SEC;
// 确保非负
if (tg->bytes_disp[READ] < 0)
tg->bytes_disp[READ] = 0;
if (tg->iops_disp[READ] < 0)
tg->iops_disp[READ] = 0;
tg->last_update = now;
}
高级性能优化
CPU 性能深度调优
优化 1: CPU 绑核 + CGroups 组合
场景:高性能计算 (HPC)
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 创建 cpuset 控制组
$ sudo cgcreate -g cpuset:/hpc/highperf
# 2. 绑定物理核心 0-7
$ echo "0-7" > /sys/fs/cgroup/cpuset/hpc/highperf/cpuset.cpus
$ echo "0" > /sys/fs/cgroup/cpuset/hpc/highperf/cpuset.mems
# 3. 创建 cpu 控制组
$ sudo cgcreate -g cpu:/hpc/highperf
# 4. 设置 CPU 配额 (无限制)
$ echo "max" > /sys/fs/cgroup/cpu/hpc/highperf/cpu.max
# 5. 设置最高权重
$ echo "10000" > /sys/fs/cgroup/cpu/hpc/highperf/cpu.weight
# 6. 启用实时调度
$ echo "1" > /sys/fs/cgroup/cpu/hpc/highperf/cpu.rt_runtime_us
性能提升:
├─ 减少上下文切换:90%+
├─ 降低缓存失效:80%+
├─ 提升计算性能:30-50%
└─ 稳定低延迟:<100μs
优化 2: CPU 隔离域
场景:延迟敏感应用
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 内核参数隔离 (grub 配置)
GRUB_CMDLINE_LINUX="isolcpus=4-7 nohz_full=4-7 rcu_nocbs=4-7"
# 2. 创建隔离控制组
$ sudo cgcreate -g cpuset:/isolated
$ echo "4-7" > /sys/fs/cgroup/cpuset/isolated/cpuset.cpus
# 3. 禁用负载均衡
$ echo "0" > /sys/fs/cgroup/cpuset/isolated/cpuset.sched_load_balance
# 4. 运行应用
$ sudo cgexec -g cpuset:isolated ./latency_sensitive_app
性能指标:
├─ 延迟抖动:降低 95%
├─ 尾延迟 (P99): 降低 80%
├─ 最大延迟:<1ms
└─ 延迟标准差:<100μs
优化 3: CPU 抢占控制
场景:实时系统
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 启用实时调度
$ sudo cgcreate -g cpu:/realtime
$ echo "950000 1000000" > /sys/fs/cgroup/cpu/realtime/cpu.rt_runtime_us
$ echo "1000000" > /sys/fs/cgroup/cpu/realtime/cpu.rt_period_us
# 2. 设置实时优先级
$ sudo cgset -r cpu.rt_priority=99 realtime
# 3. 运行实时应用
$ sudo cgexec -g cpu:realtime ./realtime_app
调度策略对比:
SCHED_FIFO (实时):
├─ 优先级:99 (最高)
├─ 可抢占低优先级
├─ 直到阻塞或自愿让出
└─ 延迟:<10μs
SCHED_OTHER (普通):
├─ 优先级:0
├─ CFS 公平调度
├─ 基于 vruntime
└─ 延迟:1-10ms
内存性能深度调优
优化 1: 内存预留 + 锁定
场景:数据库应用
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 创建内存控制组
$ sudo cgcreate -g memory:/database
# 2. 设置硬限制
$ echo "8589934592" > /sys/fs/cgroup/memory/database/memory.limit_in_bytes
# 8GB
# 3. 设置软限制 (预留)
$ echo "4294967296" > /sys/fs/cgroup/memory/database/memory.soft_limit_in_bytes
# 4GB
# 4. 禁用 OOM Kill
$ echo "1" > /sys/fs/cgroup/memory/database/memory.oom_kill_disable
# 5. 设置内存阈值告警
$ echo "8053063680" > /sys/fs/cgroup/memory/database/memory.usage_in_bytes
# 7.5GB (90% 告警)
# 6. 应用层锁定内存
$ sudo cgexec -g memory:database ./mysqld --lock-memory
性能提升:
├─ 避免 Swap: 100%
├─ 减少缺页中断:90%
├─ 查询延迟稳定:P99 < 10ms
└─ 吞吐量提升:40%
优化 2: 大页内存优化
场景:内存数据库
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 启用大页
$ echo 4096 > /proc/sys/vm/nr_hugepages
# 4096 个 2MB 大页 = 8GB
# 2. 创建控制组
$ sudo cgcreate -g hugetlb:/hugepage_db
# 3. 设置大页限制
$ echo "8589934592" > /sys/fs/cgroup/hugetlb/hugepage_db/hugetlb.2MB.max
# 4. 应用使用大页
$ sudo cgexec -g hugetlb:hugepage_db ./redis-server \
--hugepages-enabled
性能对比:
标准页 (4KB):
├─ TLB 命中率:60-70%
├─ 页表大小:2MB
├─ 缺页中断:1000 次/秒
└─ 内存访问延迟:100ns
大页 (2MB):
├─ TLB 命中率:95%+
├─ 页表大小:4KB
├─ 缺页中断:<10 次/秒
└─ 内存访问延迟:50ns
优化 3: 内存压力控制
场景:多租户环境
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 监控内存压力
$ cat /sys/fs/cgroup/memory/database/memory.pressure_level
low|medium|critical
# 2. 设置压力事件通知
$ cgroup-event-listener /sys/fs/cgroup/memory/database \
memory.pressure_level medium
# 3. 配置分层回收
$ echo "1" > /sys/fs/cgroup/memory/database/memory.use_hierarchy
# 4. 设置回收阈值
$ echo "6442450944" > /sys/fs/cgroup/memory/database/memory.high
# 6GB (触发主动回收)
回收策略:
├─ low: 被动回收
├─ medium: 主动回收
└─ critical: 强制回收 + OOM
I/O 性能深度调优
优化 1: I/O 调度器优化
场景:高 IOPS 应用
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 查看当前调度器
$ cat /sys/block/sda/queue/scheduler
[mq-deadline] kyber bfq none
# 2. 更改为 none (NVMe SSD)
$ echo none > /sys/block/sda/queue/scheduler
# 3. 创建 I/O 控制组
$ sudo cgcreate -g blkio:/highio
# 4. 设置最高权重
$ echo "1000" > /sys/fs/cgroup/blkio/highio/blkio.weight
# 5. 禁用限流
$ echo "8:0 rbps=max" > /sys/fs/cgroup/blkio/highio/io.max
$ echo "8:0 wbps=max" > /sys/fs/cgroup/blkio/highio/io.max
# 6. 设置 I/O 优先级
$ sudo ionice -c 1 -n 0 -p $(pidof app)
性能对比:
调度器 随机读 IOPS 随机写 IOPS 延迟
mq-deadline 500K 300K 200μs
kyber 600K 400K 150μs
bfq 400K 350K 300μs
none 800K 600K 100μs
优化 2: 直接 I/O + 异步 I/O
场景:数据库存储引擎
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 1. 启用 AIO
$ sudo cgcreate -g blkio:/aio_db
# 2. 使用 O_DIRECT 标志
$ sudo cgexec -g blkio:aio_db ./mysqld \
--innodb-flush-method=O_DIRECT
# 3. 配置 AIO 队列深度
$ echo 256 > /sys/block/sda/queue/nr_requests
# 4. 增加 AIO 上下文
$ echo 65536 > /proc/sys/fs/aio-max-nr
性能提升:
├─ 绕过页面缓存:减少内存拷贝
├─ 异步 I/O: 提升并发
├─ I/O 延迟:降低 60%
└─ 吞吐量:提升 3 倍
优化 3: I/O 隔离
场景:多租户存储
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 租户 A (高优先级)
$ sudo cgcreate -g blkio:/tenant_a
$ echo "8:0 rbps=104857600" > /sys/fs/cgroup/blkio/tenant_a/io.max
# 100MB/s 读
$ echo "8:0 wbps=52428800" > /sys/fs/cgroup/blkio/tenant_a/io.max
# 50MB/s 写
$ echo "800" > /sys/fs/cgroup/blkio/tenant_a/blkio.weight
# 租户 B (低优先级)
$ sudo cgcreate -g blkio:/tenant_b
$ echo "8:0 rbps=52428800" > /sys/fs/cgroup/blkio/tenant_b/io.max
# 50MB/s 读
$ echo "8:0 wbps=26214400" > /sys/fs/cgroup/blkio/tenant_b/io.max
# 25MB/s 写
$ echo "200" > /sys/fs/cgroup/blkio/tenant_b/blkio.weight
隔离效果:
├─ 带宽保障:100%
├─ IOPS 隔离:95%+
├─ 延迟稳定:P99 < 5ms
└─ 无干扰:租户间独立
生产环境监控体系
Prometheus 监控指标
# CGroups 监控指标采集
scrape_configs:
- job_name: 'cgroup-metrics'
static_configs:
- targets: ['localhost:9100'] # node_exporter
# 关键指标:
# 1. CPU 指标
- container_cpu_usage_seconds_total
- container_cpu_cfs_periods_total
- container_cpu_cfs_throttled_periods_total
- container_cpu_throttled_seconds_total
# 2. 内存指标
container_memory_usage_bytes
container_memory_rss_bytes
container_memory_cache_bytes
container_memory_swap_usage_bytes
container_memory_failcnt
# 3. I/O 指标
container_fs_reads_bytes_total
container_fs_writes_bytes_total
container_blkio_device_usage_total
# 4. PIDs 指标
container_tasks_state
Grafana 仪表盘配置
{
"dashboard": {
"title": "CGroups 资源监控",
"panels": [
{
"title": "CPU 使用率与限流",
"targets": [
{
"expr": "rate(container_cpu_usage_seconds_total[5m])",
"legendFormat": "CPU 使用率"
},
{
"expr": "rate(container_cpu_cfs_throttled_periods_total[5m]) / rate(container_cpu_cfs_periods_total[5m])",
"legendFormat": "限流比例"
}
]
},
{
"title": "内存使用与 OOM",
"targets": [
{
"expr": "container_memory_usage_bytes",
"legendFormat": "总内存"
},
{
"expr": "container_memory_rss_bytes",
"legendFormat": "RSS 内存"
},
{
"expr": "increase(container_memory_failcnt[1h])",
"legendFormat": "内存分配失败"
}
]
},
{
"title": "I/O 带宽",
"targets": [
{
"expr": "rate(container_fs_reads_bytes_total[5m])",
"legendFormat": "读带宽"
},
{
"expr": "rate(container_fs_writes_bytes_total[5m])",
"legendFormat": "写带宽"
}
]
}
]
}
}
告警规则配置
groups:
- name: cgroup-alerts
rules:
# CPU 限流告警
- alert: HighCPUThrottling
expr: |
rate(container_cpu_cfs_throttled_periods_total[5m])
/ rate(container_cpu_cfs_periods_total[5m]) > 0.3
for: 5m
labels:
severity: warning
annotations:
summary: "CPU 限流严重 ({{ $value | humanizePercentage }})"
description: "容器 {{ $labels.name }} CPU 限流比例超过 30%"
# 内存接近限制
- alert: HighMemoryUsage
expr: |
container_memory_usage_bytes
/ container_spec_memory_limit_bytes > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率过高 ({{ $value | humanizePercentage }})"
description: "容器 {{ $labels.name }} 内存使用率超过 90%"
# OOM 事件
- alert: ContainerOOMKilled
expr: increase(container_oom_killed_total[1h]) > 0
labels:
severity: critical
annotations:
summary: "容器被 OOM Kill"
description: "容器 {{ $labels.name }} 被 OOM Kill"
# I/O 限流
- alert: HighIOThrottling
expr: |
rate(container_blkio_device_usage_total[5m])
> 100 * 1024 * 1024 # 100MB/s
for: 10m
labels:
severity: warning
annotations:
summary: "I/O 带宽接近限制"
description: "容器 {{ $labels.name }} I/O 带宽持续高位"
本文档属于 Linux 内核容器技术深度解析系列
第二篇:CGroups 资源限制核心技术(第二部分 - 深度优化)
版本:V2.0 (深度优化版)
最后更新:2026 年 3 月
技术难度:⭐⭐⭐⭐⭐ (专家级)
字数:约 1.8 万字
更多推荐



所有评论(0)