漫谈cgroup

news2024/9/20 22:41:32

什么是cgroup

cgroup 是linux内核的一个功能,用来限制、控制与分离一个进程组的资源(如CPU、内存、磁盘I/O等)。它是由 Google 的两位工程师进行开发的,自 2008 年 1 月正式发布的 Linux 内核 v2.6.24 开始提供此能力。

cgroup 到目前为止,有两个大版本, cgroup v1 和 v2 。以下内容以 cgroup v2 版本为主,涉及两个版本差别的地方会在下文详细介绍。

cgroup 主要限制的资源是:

  • CPU
  • 内存
  • 网络
  • 磁盘 I/O

当我们将可用系统资源按特定百分比分配给 cgroup 时,剩余的资源可供系统上的其他 cgroup 或其他进程使用。

cgroup 的组成

cgroup 代表“控制组”,并且不会使用大写。cgroup 是一种分层组织进程的机制, 沿层次结构以受控的方式分配系统资源。我们通常使用单数形式用于指定整个特征,也用作限定符如 “cgroup controller”

cgroup 主要有两个组成部分:

  • core - 负责分层组织过程;
  • controller - 通常负责沿层次结构分配特定类型的系统资源。每个 cgroup 都有一个 cgroup.controllers 文件,其中列出了所有可供 cgroup 启用的控制器。当在 cgroup.subtree_control 中指定多个控制器时,要么全部成功,要么全部失败。在同一个控制器上指定多项操作,那么只有最后一个生效。每个 cgroup 的控制器销毁是异步的,在引用时同样也有着延迟引用的问题;

所有 cgroup 核心接口文件都以 cgroup 为前缀。每个控制器的接口文件都以控制器名称和一个点为前缀。控制器的名称由小写字母和“”组成,但永远不会以“”开头。

cgroup 的核心文件

  • cgroup.type - (单值)存在于非根cgroup 上的可读写文件。 通过将"threaded" 写入该文件,可以将 cgroup 转换为线程 cgroup,可选择 4 种取值,如下:

    1. domain - 一个正常的有效域 cgroup
    2. domain threaded - 线程子树根的线程域 cgroup
    3. domain invalid - 无效的 cgroup
    4. threaded - 线程 cgroup,线程子树
  • cgroup.procs - (换行分隔)所有 cgroup 都有的可读写文件。每行列出属于 cgroup 的进程的 PID。PID 不是有序的,如果进程移动到另一个 cgroup ,相同的 PID 可能会出现不止一次;

  • cgroup.controllers - (空格分隔)所有 cgroup 都有的只读文件。显示 cgroup 可用的所有控制器;

  • cgroup.subtree_control - (空格分隔)所有 cgroup 都有的可读写文件,初始为空。如果一个控制器在列表中出现不止一次,最后一个有效。当指定多个启用和禁用操作时,要么全部成功,要么全部失败。

  1. 以“+”为前缀的控制器名称表示启用控制器
  2. 以“-”为前缀的控制器名称表示禁用控制器
  • cgroup.events - 存在于非根 cgroup 上的只读文件。
  1. populated - cgroup 及其子节点中包含活动进程,值为1;无活动进程,值为0.
  2. frozen - cgroup 是否被冻结,冻结值为1;未冻结值为0.
  • cgroup.threads - (换行分隔)所有 cgroup 都有的可读写文件。每行列出属于 cgroup 的线程的 TID。TID 不是有序的,如果线程移动到另一个 cgroup ,相同的 TID 可能会出现不止一次。
  • cgroup.max.descendants - (单值)可读写文件。最大允许的 cgroup 数量子节点数量。
  • cgroup.max.depth - (单值)可读写文件。低于当前节点最大允许的树深度。
  • cgroup.stat - 只读文件。
  1. nr_descendants - 可见后代的 cgroup 数量。
  2. nr_dying_descendants - 被用户删除即将被系统销毁的 cgroup 数量。
  • cgroup.freeze - (单值)存在于非根 cgroup 上的可读写文件。默认值为0。当值为1时,会冻结 cgroup 及其所有子节点 cgroup,会将相关的进程关停并且不再运行。冻结 cgroup 需要一定的时间,当动作完成后, cgroup.events 控制文件中的 “frozen” 值会更新为“1”,并发出相应的通知。cgroup 的冻结状态不会影响任何 cgroup 树操作(删除、创建等);
  • cgroup.kill - (单值)存在于非根 cgroup 上的可读写文件。唯一允许值为1,当值为1时,会将 cgroup 及其所有子节点中的 cgroup 杀死(进程会被 SIGKILL 杀掉)。一般用于将一个 cgroup 树杀掉,防止叶子节点迁移;

cgroup 的归属和迁移

系统中的每一个进程都属于一个cgroup,一个进程的所有线程都属于同一个cgroup。一个进程可以从一个cgroup 迁移到另一个cgroup.进程的迁移不会影响现有的后代进程所属的cgroup.

image-20230128151018618

跨cgroup 迁移进程是一项代价昂贵的操作并且有状态的资源限制(如内存)不会动态的应用于迁移。因此,经常跨cgroup迁移进程只是作为一种手段。不鼓励直接应用不同的资源限制。

如何实现跨 cgroup 迁移

每个cgroup 都有一个可读写的接口文件 “cgroup.procs” 。每行一个 PID 记录 cgroup 限制管理的所有进程。一个进程可以通过将其 PID 写入另一 cgroup 的 “cgroup.procs” 文件来实现迁移。

但这种方式,只能迁移一个进程在单个write(2)上的调用(如果一个进程有多个线程,则会同时迁移所有线程,但也要参考线程子树,是否有将进程的线程放入不同的 cgroup 的记录)。

当一个进程fork出一个子进程的时候,该进程就诞生在其父进程所属的cgroup中。

一个没有任何子进程或活动进程的 cgroup 是可以通过删除目录进行销毁的(即使存在关联的僵尸进程,也被认为是可以被删除的)。

什么是 cgroups

当明确提到多个单独的控制组时,才使用复数形式 “cgroups” 。

cgroups 形成了树状结构。(一个给定的 cgroup 可能有多个子 cgroup 形成一棵树结构体)每个非根 cgroup 都有一个 cgroup.events 文件,其中包含 populated 字段指示 cgroup 的子层次结构是否具有实时进程。所有非根的 cgroup.subtree_control 文件,只能包含在父级中启用的控制器。

image-20230128170512470

如图所示,cgroup1 中限制了使用 cpu 及 内存资源,它将控制子节点的 CPU 周期和内存分配(即,限制 cgroup2、cgroup3、cgroup4 中的cpu及内存资源分配)。cgroup2 中启用了内存限制,但是没有启用cpu的资源限制,这就导致了 cgroup3 和 cgroup4 的内存资源受 cgroup2中的 mem 设置内容的限制;cgroup3 和 cgroup4 会自由竞争在 cgroup1 的 cpu 资源限制范围内的 cpu 资源。

由此,也可以明显的看出 cgroup 资源是自上而下分布约束的。只有当资源已经从上游 cgroup 节点分发给下游时,下游的 cgroup 才能进一步分发约束资源。所有非根的 cgroup.subtree_control 文件只能包含在父节点的 cgroup.subtree_control 文件中启用的控制器内容。

那么,子节点 cgroup 与父节点 cgroup 是否会存在内部进程竞争的情况呢

当然不会。cgroup v2 中,设定了非根 cgroup 只能在没有任何进程时才能将域资源分发给子节点的 cgroup。简而言之,只有不包含任何进程的 cgroup 才能在其 cgroup.subtree_control 文件中启用域控制器,这就保证了,进程总在叶子节点上。

挂载和委派

cgroup 的挂载方式

  • memory_recursiveprot - 递归地将 memory.min 和 memory.low 保护应用于整个子树,无需显式向下传播到叶节点的 cgroup 中,子树内叶子节点可以自由竞争;
  • memory_localevents - 只能挂载时设置或者通过从 init 命名空间重新挂载来修改,这是系统范围的选项。只用当前 cgroup 的数据填充 memory.events,如果没有这个选项,默认会计数所有子树;
  • nsdelegate - 只能挂载时设置或者通过从 init 命名空间重新挂载来修改,这也是系统范围的选项。它将 cgroup 命名空间视为委托边界,这是两种委派 cgroup 的方式之一;

cgroup 的委派方式

  • 设置挂载选项 nsdelegate ;
  • 授权用户对目录及其 cgroup.procscgroup.threadscgroup.subtree_control 文件的写访问权限

两种方式的结果相同。一旦被委派,用户就可以在目录下建立子层次结构,所有的资源分配都受父节点的制约。目前,cgroup 对委托子层次结构中的 cgroup 数量或嵌套深度没有任何限制(之后可能会受到明确限制)。

前面提到了跨 cgroup 迁移,从委派中,我们可以很明确的得知跨 cgroup 迁移对于普通用户来讲,是有限制条件的。即,是否对目前 cgroup 的 “cgroup.procs” 文件具有写访问权限以及是否对源 cgroup 和目标 cgroup 的共同祖先的 “cgroup.procs” 文件具有写访问权限。

委派和迁移

image-20230128174451413

如图,普通用户 User0 具有 cgroup[1-5] 的委派权限。

为什么 User0 想将进程 从 cgroup3 迁移至 cgroup5会失败呢?

这是由于 User0 的权限只到 cgroup1 和 cgroup2 层,并不具备 cgroup0 的权限。而委派中的授权用户明确指出需要共同祖先的 “cgroup.procs” 文件具有写访问权限!(即,需要图中 cgroup0 的权限,才可以实现)

资源分配模型及功能

以下是 cgroups 的资源分配模型:

  • 权重 - (例如,cpu.weight) 所有权重都在 [1, 10000] 范围内,默认值为 100。按照权重比率来分配资源。
  • 限制 - [0, max] 范围内,默认为“max”,即 noop(例如,io.max)。限制可以被过度使用(子节点限制的总和可能超过父节点可用的资源量)。
  • 保护 - [0, max] 范围内,默认为 0,即 noop(例如,io.low)。保护可以是硬保证或尽力而为的软边界,保护也可能被过度使用。
  • 分配 - [0, max] 范围内,默认为 0,即没有资源。分配不能被过度使用(子节点分配的总和不能超过父节点可用的资源量)。

cgroups 提供了如下功能:

  • 资源限制 - 上面 cgroup 部分已经示例,cgroups 可以以树状结构来嵌套式限制资源。
  • 优先级 - 发生资源争用时,优先保障哪些进程的资源。
  • 审计 - 监控及报告资源限制及使用。
  • 控制 - 控制进程的状态(起、停、挂起)

cgroup v1 与 cgroup v2

被弃用的核心功能

cgroup v2 和 cgroup v1 有很大的不同,我们一起来看看在 cgroup v2 中弃用了哪些 cgroup v1 的功能:

  • 不支持包括命名层次在内的多个层次结构;

  • 不支持所有 v1 安装选项;

  • “tasks” 文件被删除,“cgroup.procs” 没有排序

    • 在 cgroup v1 中线程组 ID 的列表。不保证此列表已排序或没有重复的 TGID,如果需要此属性,用户空间应排序/统一列表。将线程组 ID 写入此文件会将该组中的所有线程移动到此 cgroup 中;
  • cgroup.clone_children 被删除。clone_children 仅影响 cpuset controller。如果在 cgroup 中启用了 clone_children (设置:1),新的 cpuset cgroup 将在初始化期间从父节点的 cgroup 复制配置;

  • /proc/cgroups 对于 v2 没有意义。改用根目录下的“cgroup.controllers”文件;

cgroup v1 的问题

cgroup v2 和 v1 中最显著的不同就是 cgroup v1 允许任意数量的层次结构, 但这会带来一些问题的。我们来详细聊聊。

挂载 cgroup 层次结构时,你可以指定要挂载的子系统的逗号分隔列表作为文件系统挂载选项。默认情况下,挂载 cgroup 文件系统会尝试挂载包含所有已注册子系统的层次结构。

如果已经存在具有完全相同子系统集的活动层次结构,它将被重新用于新安装。

如果现有层次结构不匹配,并且任何请求的子系统正在现有层次结构中使用,则挂载将失败并显示 -EBUSY。否则,将激活与请求的子系统相关联的新层次结构。

当前无法将新子系统绑定到活动 cgroup 层次结构,或从活动 cgroup 层次结构中取消绑定子系统。当 cgroup 文件系统被卸载时,如果在顶级 cgroup 之下创建了任何子 cgroup,即使卸载,该层次结构仍将保持活动状态;如果没有子 cgroup,则层次结构将被停用。

这就是 cgroup v1 中的问题,在 cgroup v2 中就很好的进行了解决。

cgroup 和容器的联系

这里我们以 Docker 为例。 创建一个容器,并对其可使用的 CPU 和内存进行限制:

➜  ~ docker run --rm -d  --cpus=2 --memory=2g --name=2c2g redis:alpine 
e420a97835d9692df5b90b47e7951bc3fad48269eb2c8b1fa782527e0ae91c8e
➜  ~ cat /sys/fs/cgroup/system.slice/docker-`docker ps -lq --no-trunc`.scope/cpu.max
200000 100000
➜  ~ cat /sys/fs/cgroup/system.slice/docker-`docker ps -lq --no-trunc`.scope/memory.max
2147483648
➜  ~ 
➜  ~ docker run --rm -d  --cpus=0.5 --memory=0.5g --name=0.5c0.5g redis:alpine
8b82790fe0da9d00ab07aac7d6e4ef2f5871d5f3d7d06a5cdb56daaf9f5bc48e
➜  ~ cat /sys/fs/cgroup/system.slice/docker-`docker ps -lq --no-trunc`.scope/cpu.max       
50000 100000
➜  ~ cat /sys/fs/cgroup/system.slice/docker-`docker ps -lq --no-trunc`.scope/memory.max
536870912

从上面的示例可以看到,当我们使用 Docker 创建出新的容器并且为他指定 CPU 和 内存限制后,其对应的 cgroup 配置文件的 cpu.maxmemory.max都设置成了相应的值。

如果你想要对一些已经在运行的容器进行资源配额的检查的话,也可以直接去查看其对应的配置文件中的内容。

总结

以上就是关于容器技术的基石之一的 cgroup 的详细介绍了。接下来我还会写关于 namespace 以及其他容器技术相关的内容,敬请关注!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/182671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第30天 二叉树 java :39. 组合总和 40.组合总和II 131.分割回文串

文章目录LeetCode 39. 组合总和本题题解思路LeetCode 40.组合总和II本题题解思路LeetCode 131.分割回文串本题题解思路那么在代码里什么是切割线呢?那么在代码里什么是切割线呢?总结LeetCode 39. 组合总和 本题题解 思路 根据递归三部曲来分析 递归函…

单板硬件设计:存储器

在单板设计中,无论是涉及到一个简易的CPU、MCU小系统或者是复杂的单板设计,都离不开存储器设计: 1、存储器介绍 存储器的分类大致可以划分如下: ROM和RAM指的都是半导体存储器,ROM在系统停止供电的时候仍然可以保持…

visudo配置sudo权限

visudo配置sudo权限配置visudo仅允许字符终端登陆(tty)--授权localhost允许图形和tty登陆--授权all用户组提权-示例配置在sudoers.d目录下创建授权文件--推荐五段式配置三段式配置检查sudoers配置是否有误如何在sudo运行的命令中防止使用参数结果验证配置visudo https://blog.…

【数据结构】8.2 插入排序

文章目录前言1. 直接插入排序直接插入排序算法直接插入排序性能分析2. 折半插入排序3. 希尔排序希尔排序算法希尔排序算法分析排序方法比较前言 类似于俺们打牌时的插入,每抓来一张牌的时候,就将它放在合适的位置上,插入一张牌之后手里的牌仍…

MQ相关概念

1) 队列管理器 队列管理器是MQ系统中最上层的一个概念,由它为我们提供基于队列的消息服务。 2) 消息 在MQ中,我们把应用程序交由MQ传输的数据定义为消息,我们可以定义消息的内容并对消息进行广义的理解,比如:用户的各种…

JavaWeb-FilterListener

JavaWeb-Filter&Listener 1,Filter 1.1 Filter概述 Filter 表示过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。 如下图所示,浏览器可以访问服…

JAVA性能统计项目

一、项目背景:我们希望设计开发一个小的框架,能够获取接口调用的各种统计信息,比如,响应时间的最大值(max)、最小值(min)、平均值(avg)、百分位值&#xff08…

力扣OJ(2000+)

目录 2032. 至少在两个数组中出现的值 2037. 使每位学生都有座位的最少移动次数 2042. 检查句子中的数字是否递增 2097. 合法重新排列数对 2180. 统计各位数字之和为偶数的整数个数 2185. 统计包含给定前缀的字符串 2283. 判断一个数的数字计数是否等于数位的值 2287. …

基于MBD 的软件品质保证技术

基于MBD的软件是什么? 基于MBD的软件是基于模型开发的软件,主要应用于汽车、电子电气、机器人、航空、航天等行业。 ​​​ 与使用现有代码开发程序的方法不同,MBD 方法包括首先开发模型,将模型转换为代码,然后基于转换…

Ansys Speos | 2023R1 动态仿真助力车灯早期优化

前言 光学仿真是产品设计师应用的关键工具之一,能让用户在制作物理原型之前就通过数字环境体验产品。这对汽车领域来说显得尤为重要,随着汽车照明功能(如转向指示灯)越来越生动,TIER-1 需要能够在样件前,通…

Mac安装android studio

1. 下载as 下载地址 2. 安装 3. 启动软件 4.创建新项目 选择空白活动 名字为FirstApp,语言选择java 等待项目加载完毕 项目加载完毕 5.创建设备 6. 启动项目

【28】C语言 | 关于指针练习(1)

目录 1、下列输出什么 2、计算求和 3、使用指针打印数组内容 4、打印水仙花数 5、写一个函数,可以逆序一个字符串的内容 6、题目名称:打印菱形 6、喝汽水 7、猜名次 8、下列关于整形数组输出什么并解释 9、下列关于字符数组输出什么并解释 9.1 下列关于字…

【C++详解】——初识STL(string类的使用)

📖 前言:STL(standard template libaray-标准模板库):是C标准库的重要组成部分,不仅是一个可复用的组件库,而且一个包罗数据结构与算法的软件框架。 目录🕒 1. string 概述🕒 2. 标准库中的stri…

【小程序 | 黑马优选】tabBar、首页制作

文章目录tabBar制作首页制作配置网络请求制作轮播图效果渲染轮播图的UI解构配置小程序分包点击轮播图跳转到商品详情页面封装 uni.$showMsg() 方法分类导航区制作楼层区域制作tabBar制作 在 pages 目录中,创建首页(home)、分类(cate)、购物车(cart)、我的(my) 这 4…

windows下zookeeper搭建

程序包下载 官网下载地址 下载解压后如下! 注意,zookeeper需要java环境,如果配置了JAVA_HOME那最好,如果没配置就会出现点击bin下的zkServer.cmd后CMD窗口一闪而过 修改配置 如果本地端口没有特别要求可以直接复制conf下的zo…

多臂PEG衍生物8-Arm PEG-SAA,8-Arm PEG-Succinamide Acid,八臂PEG丁二酸酰胺

一:产品描述 1、名称 英文:8-Arm PEG-SAA,8-Arm PEG-Succinamide Acid 中文:八臂-聚乙二醇-丁二酸酰胺 2、CAS编号:N/A 3、所属分类:Carboxylic acid PEG Multi-arm PEGs 4、分子量:可定制…

IDEA新建js项目(hello)和执行js脚本

一)、安装Node.js具体操作参考:https://blog.csdn.net/xijinno1/article/details/128774375二)、IDEA中新建js项目(hello world)1.按照下图,新建js项目2.选中示例代码文件后点击鼠标右键,选中菜单栏中的 运行* 栏目运行代码(第一次运行代码的方式)3.若是…

【版本控制】Git快速上手

Do you know what Git is? 一.引入 (1) 作用 Git 是一个分布式版本控制系统,主要是用于管理开发过程中的源代码文件(Java类,xml文件,html页面等)。可用于代码回溯,版本切换,多人协作…

AcWing 292. 炮兵阵地(状态压缩DP)

AcWing 292. 炮兵阵地(状态压缩DP)一、题目二、思路1、分析2、状态表示3、状态转移4、循环设计5、初末状态三、代码一、题目 二、思路 1、分析 这道题的话和我们之前讲解的AcWing 327. 玉米田(状态压缩DP)和AcWing 1064. 小国王…

Jenkins环境搭建与实战

Jenkins环境搭建与实战1、Jenkins2、GItLab的安装2.1、安装依赖2.1.1、CentOS8安装报错2.1.2、找不到对应包安装报错2.2、配置镜像2.3、安装gitlab3、安装Jenkins4、Maven安装4.1、出现报错 The JAVA_HOME environment variable is not defined correctly的错误5、Jenkins 通过…