cgroup基础介绍

news2024/12/26 23:26:09

一项新概念的产生,必然有其原因,cgroup也不例外,最初由谷歌工程师Paul Menage和Rohit Seth提出【1】:因为计算机硬件能力越来越强大,为了提高机器的使用效率,可以在同一台机器上运行不同运算模型的工作。开始是用process container来命名,后来因为Container有多重含义容易引起误解,就在2007年更名为Control Groups,并被整合进2.6.24内核,它可以限制、记录、隔离进程组所使用的物理资源(如cpu/memory/io等等)及控制使用物理资源的优先级,本文主要参照kernel-5.10源码,对cgroup做下基础介绍。

1.cgroup的组成

我们使用cgroup对进程组做资源处理,离不开下面的组成因素:

7269edef25c970b3fb0c321d74e69fbe.png

cgroupv1可以允许多个层级,以v1的组织方式,如果把用到的子系统attach到同一个层级,子系统的资源控制没有办法解耦,可能会有某些进程受到其它子系统的影响,因此v1需要多个层级的组织方式,把一个层级看做一棵树,可以认为是一个森林。

另外,cgroup、task、subsystem以及hierarchy四者间的相互关系及其基本规则如下:

  1. 同一个hierarchy可以附加一个或多个subsystem。

  2. 一个subsystem可以附加到多个hierarchy,当且仅当这些hierarchy只有唯一这个subsystem。

  3. 对于你创建的每个hierarchy,task只能存在于其中一个cgroup中,即一个task不能存在于同一个hierarchy的不同cgroup中,但是一个task可以存在在不同hierarchy中的多个cgroup中。

  4. 进程(task)在fork自身时创建的子任务(child task)默认与原task在同一个cgroup中,但是child task允许被移动到不同的cgroup中。

1.1 subsystem 介绍

子系统主要用来实现资源的控制,因为是具体的控制模块,单独拉出来介绍,随着需求及功能的增加,有如下比较重要且常用的子系统:

475be6438b74f62cc636874cb1b6ec3b.png

cgroup抽离出这些子系统,也是在复用这些资源管理模块,其本质是在这些资源管理模块上附加钩子来实现资源的限制与优先级分配。

1.2 cgroup 关键数据结构

我们感兴趣的是task和cgroup怎样映射的,因为系统可能会有多个层级,每个task也可能会被多个子系统约束,因此一个task可能会存在于多个cgroups中;而每个cgroup中也会控制多个tasks。因此task和cgroup是多对多的关系。为了记录这种关系,可以多加链表,但那样查找及修改效率太差,linux 用css_set和cgrp_cset_link 这两个中间数据结构来完成这个映射。

试想当一个进程克隆子进程时,如果没有指定克隆到某个特定的cgroup,默认子进程会与该进程保持在相同的cgroups中,把共享相同cgroups的这组进程抽离出来,用css_set来标识,每个进程只存在于一个css_set中,一个css_set可能会包含多个进程,所有的css_sets通一个哈希表来组织,当进程在cgroups之间进行迁移时,因为css_set是基于cgroup这种共性所建立的,因此css_set也可以被复用。

进程中cgroup信息:

a42312e695f9f03c201ae90d90db6c3c.png

有了css_set后,虽然相同类型的进程被链接到了一个css_set里,但还是会有css_set与cgroup多对多映射的问题,只不过css_set会比task的个数少一些,这时cgrp_cset_link来了,新增的这第三张表可以极大提高cgroup和css_sets互相查找的效率。

总体连接关系:

3cbb4c971f24825b98624edac0250739.png

另外,css_set一方面记录该cset中的进程信息,也维护了subsys子系统的信息(简称css),也可以认为是两者之间的纽带。

css_set关键成员:

65c6b7661f09840507205b012045a67d.png

ec04b98cf9a813af5f83d93760344691.png

cgroup关键成员:

efc228c190ff41e38eb5b7c97a6bc9ee.png

8aa23c4db4a95c5aa835f8adce0549ef.png

cgroup_subsys_state,cgroup操作的关键对象,包含文件暴露,子系统操作相关。

其关键成员:

45f73833f52320e4beafaf8fe9be87ef.png

cgroup_subsys子系统,主要包含各子系统的通用操作方法。

关键成员:

ff2972002f3a63c203575ae86888bcd5.png

cgroup各数据结构关系图:

1674f152155992e33c18dadb829aa9e6.png

2. cgroup初始化

cgroup初始化比较简单,主要分两步,cgroup_init_early 和 cgroup_init。

2.1 cgroup_init_early

因为是在boot非常靠前的阶段,主要做下面的工作:

  1. 同init_task,系统也初始化了cgrp_dfl_root做为default hierarchy的cgroup_root, 同样,也有一个init_css_set,来初始化init阶段的相关task。在该阶段默认由init进程fork出来的子进程都会挂在init_css_set。

  2. 如果有相关子系统需要在init阶段被其它模块使用,会构建该子系统相关的cgroup数据结构,把相关ss/css/cgroup/css_set之间的关系建立起来,最终调用online_css来真正使该css生效,但还没有在文件系统中呈现,并初始化init_css_set的subsys。

2.2 cgroup_init

初始化走到这里,vfs及sysfs已初始化完成,主要工作:

  1. 调用cgroup_setup_root初始化cgrp_dfl_root,创建cgroup暴露给用户的相关文件,因为在default hierarchy, 会在/sys/fs/cgroup下创建cgroup_base_files数组中的相关文件,然后调用rebind_subsystems,注意这次其实没有涉及到子系统在不同hierarchy的移动,也没有使能相关的css和暴露ss相关文件。然后把目前存在的所有css_set 与root cgroup建立联系,毕竟这时都在default hierarchy下。

  2. 初始化在cgroup_subsys.h里定义好的各子系统,可见2.1。

  3. 把init_css_set挂载到cgrp_dfl_root,因此可以通过cgrp_dfl_root获取到所有挂在init_css_set里面的进程。

  4. 对每一个要初始化的子系统,初始化要暴露给用户空间的文件并创建。

  5. 因为init_css_set的subsys被初始化有变动,重新做哈希链入css_set_table。

  6. 注册cgroup和cgroup2文件系统类型。

  7. 创建/proc/cgroups文件,用来查看当前系统cgroup的概况。拿ubuntu为例,开机后只有一个hierarchy,里面创建了179个cgroup,14个子系统被使能。

cf83bf2dcd6c5c4ac1c44a2a386d16ef.png

3.cgroup创建与分配task

cgroup vfs基于kernfs,mount过程主要通过kernfs做super block及root目录初始化,另外区分了cgroupv1和cgroupv2,v2支持了thread mode, 而且只有一个‘default unified hierarchy’。因为形态的区别,v1需要查找或创建hierarchy, v2则不需要,另外mount时的参数处理也有一些区别,这里不再详述。

3.1 cgroup创建

当mount成功后,即可以在挂载的文件目录里通过mkdir创建cgroup。

主要流程如下:

  1. 找到该cgroup的父节点,并检查当前层级的一些限制是否能满足要求,主要是后代个数及深度限制。

  2. 调用cgroup_create来做具体的初始化,初始化管理其生命周期的refcnt,创建所在kernfs的目录,继承父节点目前的冻结状态,以便可以使冻结自动生效,然后把自己链入父节点的children链表,这样方便建立cgroup的树形结构,后面遍历其后代需要用到。因为在default hierarchy, 可能会使能cgroup v2,因此其subtree_control并不会被初始化。在其它层级,会对当前cgroup及其后代的subtree_control和subtree_ss_mask作初始化,两个的具体差异见前面的参数介绍。

  3. 调用css_populate_dir在当前目录下创建cgroup通用文件。

  4. 针对每个被使能的子系统,创建css及当前子系统的初始化文件(dfl_cftypes

和legacy_cftypes,但会基于是否在default hierarchy做选择创建),因此当手动mkdir cgroup时,会看到很多自动创建的文件。

3.2 分配task给cgroup

这里简单讲下thread mode,我们只能创建domain cgroup,但可以通过写入‘threaded

’ 到 当前cgroup的"cgroup.type"文件,使该cgroup变为threaded,当该cgroup变为threaded cgroup后,不能再更改为domain cgroup。变为threaded后,其最近的domain cgroup父节点会负责资源的统计,成为该threaded cgroup的dom_cgrp,如果这时候你cat下当前父节点cgroup的"cgroup.type"节点,会发现其类型从domain 变为了domain threaded,而如果该父节点所有的子孙都被删除,其又会被恢复为domain。

thread mode可以支持我们以线程粒度分组去控制,但必须在一个threaded domain中。

cgroupv1的"cgroup.procs"、"tasks",cgroupv2的"cgroup.procs"、"cgroup.threads"等节点,都可以通过写具体task pid到节点中来实现cgroup的控制。

以"cgroup.procs"为例,具体流程如下:

  1. 从用户输入获取要分配到的目的cgroup。因为是在v2 mode下操作,有区分进程和线程去分开控制,"cgroup.procs"节点会找到当前要操作的task的进程组leader,后续会把该进程组内的所有线程全部迁移到目的cgroup。

  2. 获取该task当前所在cgroup,因为是在 default hierarchy,通过cset_group_from_root去查找,查找方式也很容易理解。

  3. cgroup_attach_task 做主要的迁移动作,其中cgroup_migrate_add_src会把该线程组中的所有task所属的cset链入记录迁移过程的数据结构mgctx的preloaded_src_csets链表。

  4. cgroup_migrate_prepare_dst 先从preloaded_src_csets链表中取出源cset,叠加迁移对应的目的cgroup获取目的cset,然后记录源cset和目的cset的对应关系,另外,如果源cset与目的cset的subsys不一致,说明该子系统状态有差异,需要在迁移时重新进行can_attach和attach回调,重新纳入子系统资源管理。

  5. cgroup_migrate_add_task会把该线程组中的task的cg_list迁移到所属cset的mg_tasks链表,标记该task开始了迁移流程。随后把该cset链入mgctx的src_csets链表。

  6. cgroup_migrate_execute首先对有变动的子系统状态调用can_attach进行检测,随后会从src_csets链表中获取要迁移的cset,遍历该cset中的mg_tasks链表中的task,并取出对应目的cset,调用css_set_move_task进行迁移,rcu_assign_pointer(task->cgroups, to); 完成迁移。

4.总结

本文重点对cgroup数据结构及其基本概念进行描述,因为cgroup各数据结构稍微复杂些,所以对其做了重点描述,读者可以对照代码阅读会更有感觉。篇幅限制,具体各cgroup子系统没有涉及,抛砖引玉,感兴趣的同学可以补上。

参考资料:

【1】https://lwn.net/Articles/199643/

【2】Documentation/cgroup-v1/*

【3】Documentation/cgroup-v2.txt

【4】Kernel-5.10源码

0f9e50614436859341859a40cc056938.gif

长按关注内核工匠微信

Linux内核黑科技| 技术文章 | 精选教程

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

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

相关文章

安卓---第5章 数据存储---保存QQ账号与密码

文章目录案例1: 使用文件存储 保存QQ账号与密码功能描述saveqq_1.xmlFileSaveQQ.javasaveqq_1案例2 使用SP保存QQ账号与密码功能描述SPSaveQQ.java其他代码1. 数据存储方式2. 文件存储将数据存入文件中内部存储:外部存储:从文件中读取数据读取内部存储读…

信息系统服务管理

一、信息系统服务业及发展二、信息系统工程监理的概念及发展三、信息系统运行维护的概念和发展 IT服务管理(ITSM) 四、信息技术服务管理的标准和框架 IT服务标准体系(ITSS) 一、信息系统服务业及发展 总结:前景很好 二、信息系…

计网传输层协议:UDP和TCP

文章目录一. 应用层和传输层的联系二. UDP协议三. TCP协议1. TCP报头介绍2. TCP实现可靠传输的核心机制2.1 确认应答2.2 超时重传3. 连接管理(三次握手, 四次挥手)3.1 建立连接(三次握手)3.2 断开连接(四次挥手)4. 滑动窗口5. 流量控制6.拥塞控制7. 延时应答8. 捎带应答9. 面向…

5.InfluxDB定时任务与报警

定时任务 InfluxDB的定时任务本质上是定时执行一个Flux脚本,一般回先查询数据再聚合修改最后可以写回另外一个bucket中 常用的定时任务使用场景 降采样 : 如果数据的输入频率特别快比如IOT温度计设备每秒往InfluxDB写入一条数据会有大量的数据写入一个InfluxDB的bucket (因为…

kubernetes教程 --Pod详解

Pod详解 每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类: 用户程序所在的容器,数量可多可少 Pause容器,这是每个Pod都会有的一个根容器,它的作用有两个: 可以以它为依据,评估整个…

ADS仿真,3db均衡器是否可以补偿3db插入损耗?

背景高速信号走线经常会有走线超长的问题,走线过长带来的直接影响是对应的插入损耗IL会增加,当超过标准要求时需增加Redriver等补偿,最常用的调整时增加预加重和去加重。而调整预加重时首先遇到的一个问题是补偿多少db?是否3db的均衡就可以补…

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

摘要 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 一、双指针解析 考虑定义双指针 i , j分列数组左右两端,循环执行: 指针 i从左向右寻找偶数;指针 j从右向左寻找奇数;将偶数nums[i]和奇数 nums[j]交换。 可始终保证&…

C#:Krypton控件使用方法详解(第六讲) ——kryptonTextBox

今天介绍的Krypton控件中的kryptonTextBox,下面开始介绍这个控件的属性:首先介绍的是外观属性:Cursor属性:表示鼠标移动过该控件的时候,鼠标显示的形状。属性值如下图所示:Lines属性:表示在显示…

HTML转EXE工具(HTML App Build)最新版

HTML转EXE工具(HTM2EXE)最初发布于2022-08-17。可以将Web前端转换成Windows32或者64的EXE执行程序。当时由于时间紧,未能进行优化,特别是浏览器采用的是IE内核,所以使用起来会有一些兼容性问题,当时就记录了…

万字长文讲述由ChatGPT反思大语言模型的技术精要

文|张俊林 源|知乎张俊林 导读:ChatGPT出现后惊喜或惊醒了很多人。惊喜是因为没想到大型语言模型(LLM,Large Language Model)效果能好成这样;惊醒是顿悟到我们对LLM的认知及发展理念&#xff0c…

机器学习笔记

一 1.类型 有监督:分类、回归 无监督:聚类、降维 2.挑战: 过拟合:泛化能力弱 欠拟合:模型过于简单 二、 1.开发流程 数据收集->数据清洗->特征工程->数据建模 2.选择性能指标: 回归问题 均方根…

node-sass@4.14.1 包含风险, 如何升级依赖至 dart-sass

文章目录需求我上网都查到了哪些信息在 github 看到了 node-sass 依赖的最新版本的列表:关于方案2的失败不同版本的 nodejs 和 node-sass依赖的**适配关系**从何得知替代方案——dart-sass如何安装 dart sass?需求 在做一个基于Node、React的前端项目&a…

这才是打开Java面试的正确方式,金三银四互联网大厂Java面试八股来袭

前言 招聘旺季已经到了,不知道大家是否准备好了,面对金三银四的招聘旺季,如果没有精心准备那笔者认为那是对自己不负责任;就我们 Java 程序员来说,多数的公司总体上面试都是以自我介绍项目介绍项目细节/难点提问基础知…

【LeetCode】剑指 Offer(3)

目录 写在前面: 题目:剑指 Offer 09. 用两个栈实现队列 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 写在最后: 写在前面&…

追光进行时:沿着全光运力的新航道,加速驶向算力时代

2021年,工信部印发《新型数据中心发展三年行动计划(2021—2023年)》,明确指出“用3年时间,形成总体布局持续优化,全国一体化算力网络国家枢纽节点、省内数据中心、边缘数据中心梯次布局”,“算力…

LeetCode230218_148、654. 最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最大二叉树…

页面置换算法

页面置换算法 在进程运行过程中,若需要访问的物理块不在内存中,就需要通过一定的方式来将页面载入内存,而此时内存很可能已无空闲空间,因此就需要一定的算法来选择内存中要被置换的页面,这种算法就被称为页面置换算法…

redis容器部署及相关配置文件解释

背景:我们项目上的redis除了几个核心业务的集群部署是用二进制部署的,其他环境基本都是容器部署。所以整理了一下redis容器相关的配置。docker-compose部署的配置version: 3services:redis:image: redis:6.2.5container_name: redisrestart: alwaysports…

springmvc+jsp电影院购票售票选座推荐网站java ssm

本电影购票推荐网站以SSM作为框架,B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块:个人中心、用户管理、电影信息管理、电影类型管理、影院信息管理、系统管理、订单管理等模块,通过这些模块的实现能够基本满足日常电影购…

mysql 时区设置

方法一:修改 mysql 的配置文件永久设置时区(优点:永久保存设置,缺点:需重启MySQL服务)找到你MySQL的安装目录(如果不记得安装在哪 可以输入show variables like “%char%”; 查看)&a…