终于讲清楚了,Linux Cgroup机制以及其树形结构怎么创建的

浅谈Linux cgroup机制与YARN的CPU资源隔离 前言 在之前的这篇文章中,笔者已经讲解过了YARN是如何实现内存资源隔离的。但是只隔离内存还不够,我们在生产环境中经常可以发现有计算密集型任务争用NodeManager的CPU,以及个别Container消耗太多CPU资源导致其他系统服务抖动的情况。好在Hadoop 2.2版本之后,YARN通过利用Linux系统的cgroup机制支持了CPU资源隔离。本文先简单看看cgroup,然... 阅读详情

目录

1.cgroup基础理论和数据结构

1.1 struct cgroup_subsys是什么

1.2 struct cgroup_subsys_state是什么,以及与strcut cgroup关系

1.3 struct cgroup是什么

1.4 cgroup和subsys_cgroup是什么关系

1.5 cgroup和mem_cgroup是怎么创建出来的

1.6 /sys/fs/cgroup/memcg/test1目录结构怎么知道对应哪个控制组?

1.7 怎么知道一个进程是属于哪个控制组?

2. 源码剖析

2.1 树形结构是怎么创建起来的

cgroup_create函数

2.2 怎么遍历cgroup树


了解Linux Cgroup机制的都清楚,cgroup机制最终是通过树形结构表示的,既然是树形结构,我们必须搞清楚这个树形结构是怎么创建起来的,以及在内核源码中是怎么表达这种树形结构的,我们是否非常清楚怎么遍历整个树,本文将基于Linux5.15源码分析cgroup树形结构的创建过程。

假设我们有如下层级结构:

/sys/fs/cgroup/memcg/app

/sys/fs/cgroup/memcg/app/test1

/sys/fs/cgroup/memcg/app/test2

app就是test1和test2的父节点,test1和test2是兄弟节点,我们按照这个例子具体展开分析。

1.cgroup基础理论和数据结构

第一个很容易想到的问题就是test1是一个控制组,那么这个控制组在内核是用什么数据结构表示呢?这个数据结构还要能够表达出树形结构;同时我们怎么知道这个控制组是一个memory,还是blkio,还是其他呢?这就要从内核控制组的源码开始入手,内核通过struct cgroup表示一个控制组。

注意:这里说的cgroup并不是我们经常看到的mem_cgroup这种,cgroup结构体代表的是一个通用的控制组概念,而mem_cgroup代表的是具体的某个控制,内核称为subsys cgroup:为什么叫子控制组,因为内核中包含非常多的子控制组,比如memory或者io等等,具体在内核include/linux/cgroup_subsys.h 


/* generate an array of cgroup subsystem pointers */
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
struct cgroup_subsys *cgroup_subsys[] = {
#include <linux/cgroup_subsys.h>
};
#undef SUBSYS

#if IS_ENABLED(CONFIG_CPUSETS)
SUBSYS(cpuset)
#endif

#if IS_ENABLED(CONFIG_CGROUP_SCHED)
SUBSYS(cpu)
#endif

#if IS_ENABLED(CONFIG_CGROUP_CPUACCT)
SUBSYS(cpuacct)
#endif

#if IS_ENABLED(CONFIG_BLK_CGROUP)
SUBSYS(io)
#endif

#if IS_ENABLED(CONFIG_MEMCG)
SUBSYS(memory)
#endif

#if IS_ENABLED(CONFIG_CGROUP_DEVICE)
SUBSYS(devices)
#endif

#if IS_ENABLED(CONFIG_CGROUP_FREEZER)
SUBSYS(freezer)
#endif

#if IS_ENABLED(CONFIG_CGROUP_NET_CLASSID)
SUBSYS(net_cls)
#endif

#if IS_ENABLED(CONFIG_CGROUP_PERF)
SUBSYS(perf_event)
#endif

#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
SUBSYS(net_prio)
#endif

#if IS_ENABLED(CONFIG_CGROUP_HUGETLB)
SUBSYS(hugetlb)
#endif

#if IS_ENABLED(CONFIG_CGROUP_PIDS)
SUBSYS(pids)
#endif

#if IS_ENABLED(CONFIG_CGROUP_RDMA)
SUBSYS(rdma)
#endif

#if IS_ENABLED(CONFIG_CGROUP_MISC)
SUBSYS(misc)
#endif
1.1 struct cgroup_subsys是什么

通过上面的介绍我们知道linux内核定义类似memory,io,cpu等几种具体的子控制组,cgroup_subsys数据结构本质上其实不代表某个具体的控制组实体,而是控制组实体的操控的结构体,定义了具体控制实体的函数,比如创建一个子控制组实体mem_cgroup:

/*
 * Control Group subsystem type.
 * See Documentation/admin-guide/cgroup-v1/cgroups.rst for details
 */
struct cgroup_subsys {
	struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
	int (*css_online)(struct cgroup_subsys_state *css);
	void (*css_offline)(struct cgroup_subsys_state *css);
	void (*css_released)(struct cgroup_subsys_state *css);
	void (*css_free)(struct cgroup_subsys_state *css);
	void (*css_reset)(struct cgroup_subsys_state *css);
	void (*css_rstat_flush)(struct cgroup_subsys_state *css, int cpu);
	int (*css_extra_stat_show)(struct seq_file *seq,
				   struct cgroup_subsys_state *css);

	int (*can_attach)(struct cgroup_taskset *tset);
	void (*cancel_attach)(struct cgroup_taskset *tset);
	void (*attach)(struct cgroup_taskset *tset);
	void (*post_attach)(void);
	int (*can_fork)(struct task_struct *task,
			struct css_set *cset);
	void (*cancel_fork)(struct task_struct *task, struct css_set *cset);
	void (*fork)(struct task_struct *task);
	void (*exit)(struct task_struct *task);
	void (*release)(struct task_struct *task);
    ...
}
1.2 struct cgroup_subsys_state是什么,以及与strcut cgroup关系

我们知道cgroup_subsys不代表具体的控制组实体,那么像mem_cgroup这种具体的子控制组是用什么数据结构表示:cgroup_subsys_state,这个类是所有具体子控制组对象的基类,就是说mem_cgroup的基类就是cgroup_subsys_state。注意:struct cgroup的struct cgroup_subsys_state是通过self字段表示,主要用来表示cgroup本身,而不是指向具体的subsys cgroup,具体的subsys cgroup是有struct cgroup的subsys[]数组存储的。

/*
 * Per-subsystem/per-cgroup state maintained by the system.  This is the
 * fundamental structural building block that controllers deal with.
 *
 * Fields marked with "PI:" are public and immutable and may be accessed
 * directly without synchronization.
 */
struct cgroup_subsys_state {
	/* PI: the cgroup that this css is attached to */
	struct cgroup *cgroup;

	/* PI: the cgroup subsystem that this css is attached to */
	struct cgroup_subsys *ss;

	/* reference count - access via css_[try]get() and css_put() */
	struct percpu_ref refcnt;

	/* siblings list anchored at the parent's ->children */
	struct list_head sibling;
	struct list_head children;

	/* flush target list anchored at cgrp->rstat_css_list */
	struct list_head rstat_css_node;

	/*
	 * PI: Subsys-unique ID.  0 is unused and root is always 1.  The
	 * matching css can be looked up using css_from_id().
	 */
	int id;

	unsigned int flags;

	/*
	 * Monotonically increasing unique serial number which defines a
	 * uniform order among all csses.  It's guaranteed that all
	 * ->children lists are in the ascending order of ->serial_nr and
	 * used to allow interrupting and resuming iterations.
	 */
	u64 serial_nr;

	/*
	 * Incremented by online self and children.  Used to guarantee that
	 * parents are not offlined before their children.
	 */
	atomic_t online_cnt;

	/* percpu_ref killing and RCU release */
	struct work_struct destroy_work;
	struct rcu_work destroy_rwork;

	/*
	 * PI: the parent css.	Placed here for cache proximity to following
	 * fields of the containing structure.
	 */
	struct cgroup_subsys_state *parent;
};

struct mem_cgroup {
	struct cgroup_subsys_state css;

	/* Private memcg ID. Used to ID objects that outlive the cgroup */
	struct mem_cgroup_id id;

	/* Accounted resources */
	struct page_counter memory;		/* Both v1 & v2 */

	union {
		struct page_counter swap;	/* v2 only */
		struct page_counter memsw;	/* v1 only */
	};

	/* Legacy consumer-oriented counters */
	struct page_counter kmem;		/* v1 only */
	struct page_counter tcpmem;		/* v1 only */

	/* Range enforcement for interrupt charges */
	struct work_struct high_work;

	unsigned long soft_limit;

	/* vmpressure notifications */
	struct vmpressure vmpressure;
    ...
}

 我们知道基类一般要做一些公共的操作,那么cgroup的树形结构正好放在cgroup_subsys_state数据结构中,因为树形结构是每一种控制组都需要的基础逻辑,而某个具体的subsys cgroup可以定义该类控制组差异化的定字段。

树形结构通过cgroup_subsys_state的几个重要的字段完成:parent,sibling,children

按照本文刚开始的例子说明:

parent:当前控制组的父控制组。如果当前控制组指test1,那么parent指向的就是app控制组

children:当前控制组的子控制组。如果当前控制组是app,那么children就包括了test1,test2

sibling:兄弟控制组,test1和test2就是兄弟控制组。

那么上面的三个字段构建树形的呢?children相当于一个list_head的head,那么sibling就是add到children的每个元素,如下:

1.3 struct cgroup是什么

通过上面的分析,我们已经知道cgroup是指控制组的概念,如果我们在/sys/fs/cgroup/memcg/目录下创建一个test1目录,会触发一个cgroup_create的函数调用,也就是会创建一个cgroup,同时意味也创建了一个mem_cgroup,其实cgroup可以包含多个subsys cgroup,为什么要这样设计呢,因有的subs

Linux内存管理(101):cgroup v2 简介 术语:cgroup:control group 的缩写,永不大写(never capitalized);单数形式的 cgroup 用于指定整个特性,也用作等术语中的修饰符;复数形式的 cgroups 显式指多个独立的;cgroup 是一种机制,它将系统进程按照分层组织,并沿着这种分层以一个可控、可配置的方式来分配系统资源。 阅读详情

相关推荐

合规批量下载美国上市公司年报数据的一些经验和总结

本文总结了使用Python脚本批量下载和处理美国上市公司SEC报告的技术经验。通过CIK代码查询SEC EDGAR系统,生成特定日期和报告类型的URL,并使用Selenium和Requests库下载报告内容。流程包括数据获取、文件下载、Excel处理和多线程优化,确保高效处理几百条数据。关键技术挑战包括SEC访问限制、动态网页内容和数据完整性,解决方案包括设置合规的User-Agent、使用Selenium模拟浏览器行为以及错误日志记录。最佳实践包括模块化设计、多线程优化和严格遵守SEC合规性。该自动化流程

jyfool的博客 1635

JasperReport制作行内容合并的表格

效果图: 实现思路一: 交叉表 另一个思路: 普通表格 缺点:无法实现内容 垂直居中显示 准备工作 一、数据准备 DROP TABLE IF EXISTS `address_item_sex_value`; CREATE TABLE `address_item_sex_value` ( `id` int(11) NOT NULL AUTO_INCREM...

weixin_34148456的博客 2468

iTunes登录协议全解析:从抓包到加密参数生成(含HTTPDebugger避坑指南)

本文深度解析iTunes登录协议,提供从环境搭建、绕过反调试机制到捕获网络流量的完整实战指南。重点剖析了如何利用HTTPDebugger等工具进行抓包,并详细解读了核心加密参数X-Apple-ActionSignature的生成逻辑,为网络安全研究员和协议分析工程师提供了一份详尽的逆向分析与协议复现教程。

weixin_28314575的博客 868

瑞芯微RK3576开发板实战:6TOPS NPU如何加速你的AIoT项目(附性能测试)

本文以瑞芯微RK3576开发板为核心,深入探讨其6TOPS NPU在AIoT项目中的实战应用。通过详细的性能测试对比,展示了NPU如何将AI模型推理速度提升15倍以上,并大幅降低CPU负载。文章涵盖从环境搭建、模型转换优化到多屏异显与系统级调优的全流程,为开发者提供了将硬件算力转化为实际项目加速效果的完整指南。

oauth7security的博客 820

innovus:set_clock_latency与insertion_delay

当1ns clock latency设置在capture上,在report_timing报告中体现在other end arrival time以及capture clock path的Arrival Time上。因为-1ns的insertion delay存在,所以skew group报告中显示的Arrival (ns)是减1ns的结果,即1.819-1=0.819 ns。CTS阶段create_ccopt_clock_tree_spec之后,spec中会产生对应的insertion_delay命令。

m0_61544122的博客 1617

【已解决】WorkBuddy 国内版与国际版共存 + 关闭自动更新 教程

本文介绍在Windows系统中同时安装并共存WorkBuddy国内版与国际版的完整方案,通过修改product.json文件关闭启动自动更新,修复缓存配置污染问题,确保两版本互不干扰、数据独立。重点解决因共享身份标识导致的更新源错乱、进程锁冲突及自动覆盖风险,提供命令行备份与修改步骤,并强调手动升级时需避免使用应用内更新功能,以规避平台参数错位缺陷。

人生是一场修行 1481

OceanBase数据迁移(OMS)深度解析:异构数据库迁移方案、核心原理与实战优化指南

OceanBase迁移服务(OMS)提供异构数据库间全量+增量数据迁移与实时同步能力,核心价值在于保障业务连续性、数据一致性和异构兼容性。其分层架构包含服务接入层、流程编排层和组件链路层,支持Oracle/MySQL/DB2等与OceanBase的数据交互。关键技术包括DBCat引擎处理结构转换、并行分片实现全量迁移、以及日志解析保障增量同步。OMS通过类型映射、批量提交和断点续传等优化手段,确保迁移过程高效可靠,典型应用于去O迁移、数据库升级等场景。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 848

基于R-CNN深度学习的生活垃圾检测与分类系统:数据集、模型和UI界面的完整实现

我们将使用一个公开的垃圾分类数据集来训练我们的模型。一个常见的数据集是TACO数据集(Trash Annotations in Context),该数据集包含多种垃圾类别,适用于垃圾分类任务。TACO数据集中的图像标注了垃圾的类别以及其在图像中的位置,适合用于目标检测任务。图片数据:每张图片中包含不同种类的垃圾。标签文件:每个图像有相应的标签文件,标注了图像中垃圾的类别、位置(通常为边界框坐标)等信息。dataset/images/image1.jpgimage2.jpg......其中,

YOLO 1101

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

上一篇: [Linux Kernel Block Layer第一篇] block layer架构设计
下一篇: Linux匿名映射
OS技术解密
博客等级 码龄16年 3760粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值