当前位置: 首页 > news >正文

Linux内核中的cgroups v2资源管理技术

Linux内核中的cgroups v2资源管理技术

什么是cgroups?

cgroups(Control Groups)是Linux内核提供的一种资源管理机制,它允许我们对进程组进行资源限制、优先级设置、资源使用监控等操作。cgroups是容器技术(如Docker、Kubernetes)的核心基础之一,它为容器提供了资源隔离和限制的能力。

cgroups有两个主要版本:

  • cgroups v1:较早的版本,提供了基本的资源管理功能
  • cgroups v2:较新的版本,提供了更统一、更灵活的资源管理接口

cgroups v2的设计目标

cgroups v2的设计目标包括:

  1. 统一的层次结构:提供一个统一的层次化结构,简化资源管理
  2. 更好的资源隔离:更严格的资源隔离,避免资源竞争
  3. 更灵活的资源分配:支持动态调整资源分配
  4. 更简单的API:简化用户空间接口,降低使用复杂度
  5. 更好的安全性:增强安全特性,防止资源逃逸

cgroups v2的核心概念

1. 层次结构

cgroups v2使用一个统一的层次结构来组织进程和资源控制器:

  • 根cgroup:整个系统的根cgroup,所有进程默认属于根cgroup
  • 子cgroup:根cgroup下可以创建多个子cgroup,形成树状结构
  • 进程分配:每个进程只能属于一个cgroup,但可以从一个cgroup迁移到另一个cgroup

2. 资源控制器

cgroups v2支持多种资源控制器,用于管理不同类型的资源:

  • cpu:控制CPU时间分配
  • cpuset:控制CPU和内存节点的分配
  • memory:控制内存使用
  • io:控制块设备I/O
  • pids:控制进程数量
  • hugetlb:控制大页内存使用
  • rdma:控制RDMA资源使用

3. 挂载和管理

cgroups v2通过文件系统接口进行管理:

  • 挂载cgroup2文件系统:使用mount -t cgroup2 none /sys/fs/cgroup
  • 创建cgroup:在挂载点下创建目录
  • 管理进程:将进程ID写入cgroup.procs文件
  • 配置资源:通过写入相应的配置文件来设置资源限制

cgroups v2的使用方法

1. 基本操作

挂载cgroup2文件系统
# 挂载cgroup2文件系统 mount -t cgroup2 none /sys/fs/cgroup # 查看挂载情况 mount | grep cgroup
创建和管理cgroup
# 创建一个名为myapp的cgroup mkdir /sys/fs/cgroup/myapp # 将进程ID 1234加入到myapp cgroup echo 1234 > /sys/fs/cgroup/myapp/cgroup.procs # 查看myapp cgroup中的进程 cat /sys/fs/cgroup/myapp/cgroup.procs # 删除myapp cgroup(需要先移走所有进程) rmdir /sys/fs/cgroup/myapp

2. 资源限制配置

CPU限制
# 设置CPU权重(相对值,默认100) echo 500 > /sys/fs/cgroup/myapp/cpu.weight # 设置CPU最大使用限制(单位:微秒/毫秒,1000000表示100%) echo "max 100000" > /sys/fs/cgroup/myapp/cpu.max # 设置CPU利用率限制(单位:百分比) echo "75000 100000" > /sys/fs/cgroup/myapp/cpu.max
内存限制
# 设置内存使用上限 echo "256M" > /sys/fs/cgroup/myapp/memory.max # 设置内存软限制 echo "128M" > /sys/fs/cgroup/myapp/memory.high # 查看内存使用情况 cat /sys/fs/cgroup/myapp/memory.current
I/O限制
# 设置块设备的I/O权重 echo "8:0 500" > /sys/fs/cgroup/myapp/io.weight # 设置读操作的速率限制(单位:字节/秒) echo "8:0 rbps=1048576" > /sys/fs/cgroup/myapp/io.max # 设置写操作的速率限制 echo "8:0 wbps=2097152" > /sys/fs/cgroup/myapp/io.max
进程数量限制
# 设置最大进程数量 echo 100 > /sys/fs/cgroup/myapp/pids.max # 查看当前进程数量 cat /sys/fs/cgroup/myapp/pids.current

cgroups v2的编程接口

1. 系统调用

cgroups v2提供了以下系统调用:

  • mkdir()/rmdir():创建和删除cgroup
  • open()/read()/write():读取和写入cgroup配置文件
  • getpid()/getppid():获取进程ID
  • write():将进程加入cgroup

2. 示例代码

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> // 创建cgroup int create_cgroup(const char *path) { return mkdir(path, 0755); } // 将进程加入cgroup int add_process_to_cgroup(const char *cgroup_path, pid_t pid) { char procs_path[256]; char pid_str[16]; int fd; snprintf(procs_path, sizeof(procs_path), "%s/cgroup.procs", cgroup_path); fd = open(procs_path, O_WRONLY); if (fd < 0) { perror("open"); return -1; } snprintf(pid_str, sizeof(pid_str), "%d", pid); if (write(fd, pid_str, strlen(pid_str)) < 0) { perror("write"); close(fd); return -1; } close(fd); return 0; } // 设置CPU限制 int set_cpu_limit(const char *cgroup_path, int weight, int max_us) { char cpu_weight_path[256]; char cpu_max_path[256]; char weight_str[16]; char max_str[32]; int fd; // 设置CPU权重 snprintf(cpu_weight_path, sizeof(cpu_weight_path), "%s/cpu.weight", cgroup_path); fd = open(cpu_weight_path, O_WRONLY); if (fd < 0) { perror("open cpu.weight"); return -1; } snprintf(weight_str, sizeof(weight_str), "%d", weight); if (write(fd, weight_str, strlen(weight_str)) < 0) { perror("write cpu.weight"); close(fd); return -1; } close(fd); // 设置CPU最大使用限制 snprintf(cpu_max_path, sizeof(cpu_max_path), "%s/cpu.max", cgroup_path); fd = open(cpu_max_path, O_WRONLY); if (fd < 0) { perror("open cpu.max"); return -1; } snprintf(max_str, sizeof(max_str), "%d 1000000", max_us); if (write(fd, max_str, strlen(max_str)) < 0) { perror("write cpu.max"); close(fd); return -1; } close(fd); return 0; } // 设置内存限制 int set_memory_limit(const char *cgroup_path, const char *max) { char memory_max_path[256]; int fd; snprintf(memory_max_path, sizeof(memory_max_path), "%s/memory.max", cgroup_path); fd = open(memory_max_path, O_WRONLY); if (fd < 0) { perror("open memory.max"); return -1; } if (write(fd, max, strlen(max)) < 0) { perror("write memory.max"); close(fd); return -1; } close(fd); return 0; } int main() { const char *cgroup_path = "/sys/fs/cgroup/myapp"; pid_t pid = getpid(); // 创建cgroup if (create_cgroup(cgroup_path) < 0) { fprintf(stderr, "Failed to create cgroup\n"); return 1; } // 将当前进程加入cgroup if (add_process_to_cgroup(cgroup_path, pid) < 0) { fprintf(stderr, "Failed to add process to cgroup\n"); return 1; } // 设置资源限制 if (set_cpu_limit(cgroup_path, 500, 500000) < 0) { fprintf(stderr, "Failed to set CPU limit\n"); return 1; } if (set_memory_limit(cgroup_path, "256M") < 0) { fprintf(stderr, "Failed to set memory limit\n"); return 1; } printf("Process %d added to cgroup %s with resource limits\n", pid, cgroup_path); // 保持进程运行 while (1) { sleep(1); } return 0; }

cgroups v2与cgroups v1的区别

1. 层次结构

  • cgroups v1:每个资源控制器有独立的层次结构
  • cgroups v2:所有资源控制器共享一个层次结构

2. 资源分配模型

  • cgroups v1:使用配额和限制的方式
  • cgroups v2:使用统一的比例分配模型

3. 接口设计

  • cgroups v1:每个资源控制器有独立的文件接口
  • cgroups v2:提供统一的文件接口,简化管理

4. 安全性

  • cgroups v1:存在一些安全漏洞,如资源逃逸
  • cgroups v2:增强了安全特性,提供更严格的资源隔离

5. 兼容性

  • cgroups v1:被广泛使用,大多数容器运行时支持
  • cgroups v2:较新,正在被越来越多的系统和容器运行时采用

实际应用场景

1. 容器管理

cgroups v2是现代容器运行时(如Docker、containerd)的基础:

  • 为每个容器提供资源限制
  • 确保容器之间的资源隔离
  • 防止单个容器消耗过多系统资源

2. 服务器资源管理

在多用户或多服务的服务器上:

  • 为不同的服务分配资源份额
  • 限制单个服务的资源使用
  • 确保关键服务的资源需求

3. 边缘设备管理

在资源受限的边缘设备上:

  • 合理分配有限的资源
  • 确保核心功能的资源需求
  • 防止非关键进程消耗过多资源

4. 高性能计算

在高性能计算环境中:

  • 为不同的计算任务分配资源
  • 确保计算任务的资源需求
  • 提高资源利用率

性能优化建议

1. 合理设置资源限制

  • 根据应用的实际需求设置资源限制
  • 避免设置过于严格的限制,导致应用性能下降
  • 定期监控和调整资源限制

2. 优化cgroup层次结构

  • 保持cgroup层次结构简单,避免过深的嵌套
  • 合理组织cgroup,根据应用类型和资源需求进行分组
  • 避免创建过多的cgroup,减少管理开销

3. 监控资源使用

  • 定期监控cgroup的资源使用情况
  • 使用工具如cgroup-monitorsystemd-cgtop
  • 根据监控结果调整资源分配

4. 结合其他技术

  • 与namespaces结合使用,提供更完整的隔离
  • 与seccomp结合使用,增强安全性
  • 与Linux调度器结合使用,优化CPU分配

代码优化案例

1. 容器资源管理

// container_cgroup.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #define CGROUP_BASE "/sys/fs/cgroup" // 创建容器的cgroup int create_container_cgroup(const char *container_id) { char cgroup_path[256]; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, container_id); return mkdir(cgroup_path, 0755); } // 配置容器的资源限制 int configure_container_resources(const char *container_id, const char *cpu_weight, const char *memory_max, const char *pids_max) { char cgroup_path[256]; char file_path[256]; int fd; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, container_id); // 设置CPU权重 snprintf(file_path, sizeof(file_path), "%s/cpu.weight", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, cpu_weight, strlen(cpu_weight)); close(fd); } // 设置内存限制 snprintf(file_path, sizeof(file_path), "%s/memory.max", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, memory_max, strlen(memory_max)); close(fd); } // 设置进程数量限制 snprintf(file_path, sizeof(file_path), "%s/pids.max", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, pids_max, strlen(pids_max)); close(fd); } return 0; } // 将进程加入容器的cgroup int add_process_to_container(const char *container_id, pid_t pid) { char cgroup_path[256]; char procs_path[256]; char pid_str[16]; int fd; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, container_id); snprintf(procs_path, sizeof(procs_path), "%s/cgroup.procs", cgroup_path); fd = open(procs_path, O_WRONLY); if (fd < 0) { perror("open"); return -1; } snprintf(pid_str, sizeof(pid_str), "%d", pid); if (write(fd, pid_str, strlen(pid_str)) < 0) { perror("write"); close(fd); return -1; } close(fd); return 0; } // 清理容器的cgroup int cleanup_container_cgroup(const char *container_id) { char cgroup_path[256]; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, container_id); return rmdir(cgroup_path); } int main(int argc, char *argv[]) { if (argc != 5) { fprintf(stderr, "Usage: %s <container_id> <cpu_weight> <memory_max> <pids_max>\n", argv[0]); return 1; } const char *container_id = argv[1]; const char *cpu_weight = argv[2]; const char *memory_max = argv[3]; const char *pids_max = argv[4]; // 创建cgroup if (create_container_cgroup(container_id) < 0) { fprintf(stderr, "Failed to create container cgroup\n"); return 1; } // 配置资源限制 if (configure_container_resources(container_id, cpu_weight, memory_max, pids_max) < 0) { fprintf(stderr, "Failed to configure container resources\n"); return 1; } // 将当前进程加入cgroup if (add_process_to_container(container_id, getpid()) < 0) { fprintf(stderr, "Failed to add process to container\n"); return 1; } printf("Container %s created with resources: cpu_weight=%s, memory_max=%s, pids_max=%s\n", container_id, cpu_weight, memory_max, pids_max); // 模拟容器运行 while (1) { sleep(1); } return 0; }

2. 服务资源管理

// service_cgroup.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #define CGROUP_BASE "/sys/fs/cgroup/services" // 初始化服务cgroup层次结构 int init_service_cgroups() { return mkdir(CGROUP_BASE, 0755); } // 创建服务的cgroup int create_service_cgroup(const char *service_name) { char cgroup_path[256]; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, service_name); return mkdir(cgroup_path, 0755); } // 配置服务的资源限制 int configure_service_resources(const char *service_name, const char *cpu_weight, const char *memory_max, const char *io_weight) { char cgroup_path[256]; char file_path[256]; int fd; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, service_name); // 设置CPU权重 snprintf(file_path, sizeof(file_path), "%s/cpu.weight", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, cpu_weight, strlen(cpu_weight)); close(fd); } // 设置内存限制 snprintf(file_path, sizeof(file_path), "%s/memory.max", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, memory_max, strlen(memory_max)); close(fd); } // 设置I/O权重 snprintf(file_path, sizeof(file_path), "%s/io.weight", cgroup_path); fd = open(file_path, O_WRONLY); if (fd >= 0) { write(fd, io_weight, strlen(io_weight)); close(fd); } return 0; } // 将服务进程加入cgroup int add_service_process(const char *service_name, pid_t pid) { char cgroup_path[256]; char procs_path[256]; char pid_str[16]; int fd; snprintf(cgroup_path, sizeof(cgroup_path), "%s/%s", CGROUP_BASE, service_name); snprintf(procs_path, sizeof(procs_path), "%s/cgroup.procs", cgroup_path); fd = open(procs_path, O_WRONLY); if (fd < 0) { perror("open"); return -1; } snprintf(pid_str, sizeof(pid_str), "%d", pid); if (write(fd, pid_str, strlen(pid_str)) < 0) { perror("write"); close(fd); return -1; } close(fd); return 0; } int main(int argc, char *argv[]) { if (argc != 5) { fprintf(stderr, "Usage: %s <service_name> <cpu_weight> <memory_max> <io_weight>\n", argv[0]); return 1; } const char *service_name = argv[1]; const char *cpu_weight = argv[2]; const char *memory_max = argv[3]; const char *io_weight = argv[4]; // 初始化服务cgroup层次结构 init_service_cgroups(); // 创建服务cgroup if (create_service_cgroup(service_name) < 0) { fprintf(stderr, "Failed to create service cgroup\n"); return 1; } // 配置资源限制 if (configure_service_resources(service_name, cpu_weight, memory_max, io_weight) < 0) { fprintf(stderr, "Failed to configure service resources\n"); return 1; } // 将当前进程加入cgroup if (add_service_process(service_name, getpid()) < 0) { fprintf(stderr, "Failed to add process to service cgroup\n"); return 1; } printf("Service %s created with resources: cpu_weight=%s, memory_max=%s, io_weight=%s\n", service_name, cpu_weight, memory_max, io_weight); // 模拟服务运行 while (1) { sleep(1); } return 0; }

总结

cgroups v2是Linux内核中一项重要的资源管理技术,它为我们提供了一种灵活、高效的方式来管理系统资源。通过cgroups v2,我们可以:

  • 对进程组进行资源限制和监控
  • 实现更严格的资源隔离
  • 为容器技术提供基础支持
  • 优化系统资源的使用

作为内核开发者和系统管理员,掌握cgroups v2技术是非常重要的。它不仅是容器技术的基础,也是系统资源管理的重要工具。

随着容器技术的不断发展和普及,cgroups v2的重要性将会越来越高。相信在不久的将来,cgroups v2将会成为Linux系统中资源管理的标准方案,为各种应用场景提供更强大、更灵活的资源管理能力。

http://www.jsqmd.com/news/589058/

相关文章:

  • Linux下C程序编译过程详解与GCC工具链使用
  • 2026年金堂护栏定制实力品牌深度测评与选购指南 - 2026年企业推荐榜
  • systemctl start mysqld的生命周期的庖丁解牛
  • Matrix Laser Sensor I²C嵌入式驱动开发与工业测距实践
  • OpenClaw语音控制之使用 Vosk 实现离线语音控制
  • Arduino/ESP32轻量级协作式任务调度库
  • C语言函数指针原理与嵌入式开发实践
  • Linux内核中的namespaces机制详解
  • PHP的每一行代码都需要CPU的参与吗?
  • 2026年湖北橡塑管市场:专业平台选择逻辑与价值构建指南 - 2026年企业推荐榜
  • 2026年文武教育新格局:深度解析嵩山少林武术学院的价值定位与选择逻辑 - 2026年企业推荐榜
  • Go语言的接口与多态
  • PyTorch 2.8通用镜像实操手册:htop监控GPU利用率与显存泄漏排查技巧
  • OpenClaw学习助手:Qwen3-14b_int4_awq自动生成知识卡片
  • OpenClaw Gateway 架构深度解析
  • micro-moustache:嵌入式轻量模板引擎
  • 2026年苏州市场AI搜索优化服务商深度评估:技术驱动与本土适配的双重考量 - 2026年企业推荐榜
  • 安平排水沟盖板供应商深度测评:2026年谁将引领行业标准? - 2026年企业推荐榜
  • OpenClaw+千问3.5-9B:自动化社交媒体内容发布方案
  • Kimi-VL-A3B-Thinking实战教程:用截图提问实现IT运维故障诊断辅助
  • DS1307实时时钟芯片驱动开发与工程实践指南
  • 2026年浙江入户门厂商综合实力榜:谁在引领高端安全与智能新趋势? - 2026年企业推荐榜
  • Go语言的反射机制详解
  • M2LOrder轻量级部署教程:Miniconda torch28环境隔离与依赖冲突解决
  • 2026年湖北十堰汽车窗帘选购指南:五大实力厂家深度测评与推荐 - 2026年企业推荐榜
  • 【2026年最新600套毕设项目分享】springboot旅游出行指南系统(14321)
  • LwEVT:嵌入式轻量级事件管理器设计与实践
  • 深蓝词库转换:跨输入法词库迁移与定制的一站式解决方案
  • ESP32嵌入式CLI库ESPShell:轻量级运行时调试方案
  • 2026企业礼品新风向:专业按摩仪服务商综合选购指南与TOP5榜单深度解析 - 2026年企业推荐榜