一、Cgroup的目的
Cgroup和namespa类似,也是将进程进程分组,但是目的与namespace不一样,namespace是为了隔离进程组之前的资源,而Cgroup是为了对一组进程进行统一的资源监控和限制。
二、为什么需要Cgroup
在Linux里,对进程进程分组,比如Session group、process group等,后来需要追踪一组进程的内存和IO使用情况,出现了cgroup,用来统一对进程进行分组,并在分组的基础上对进程进程监控和资源控制管理等。
三、Cgroup中名词概念
任务(Task) | 在Cgroup中,任务就是系统的一个进程 |
控制族群(control group) | 控制族群就是按照一组某种标准划分的进程。Cgroup中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也可以从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用cgroups以控制族群为单位分配资源,同时受到cgroups以控制族群为单位设定限制。 |
层级(hierachy) | 控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定属性 |
子系统(subsystem) | 一个子系统就是一个资源控制器 |
Cgroup可以指整个cgrop技术,也可以指一个具体的进程组。
Cgroup是Linux下一种将进程按组管理的机制,在用户层面看,Cgroup技术就是可以把系统中的所有进程组织成一颗独立的树,每颗树都包含系统所有进程,树的每个节点就是一个进程组,而每颗树又和一个或者多个subsystem关联,树的作用是对进程分组,而subsystem作用是对这些组进行操作。
- subsystem:一个subsystem就是一个内核模块,它被关联到一颗Cgroup树之后,就会对树的每个节点(进程组)上做具体操作。subsystem也被称为resource controller,因为它主要用来调度和限制每个进程组资源,有时也可以将进程分组只是为了做监控,观察进程组的状态。例如,perf_event subsystem。目前Linux支持12中system,比如限制CPU的使用时间,限制使用内存,统计CPU使用情况,冻结和恢复一组进程等。
- 下面每个子系统都需要与内核的其它模块配合来完成资源控制,比如对CPU资源的限制是通过进程调度模块根据CPU子系统的配置来完成;对内存资源的限制是内存模块根据memoty子系统的配置来完成,对网络数据包的控制则需要Traffic Control子系统配合完成。
subsystem 作用 cpu 主要限制进程CPU使用率 cpuacct 统计cgroups中进程的cpu使用率 cpuset 为cgroups中进程分配单独的CPU节点(多核)或内存节点 blkio 限制进程的块设备IO memory 限制进程的memory使用量 devices 可以控制进程能够访问某些设备 freezer 挂起或者恢复cgrops中进程 net_cls 可以标记cgroups中进程的网络数据包,然后可以使用tc(traffic control)对数据包进程控制 ns 可以使不同cgroups下面的进程使用不同的namespace
四、cgroups层级结构(Hierachy)
内核使用cgroup结构体表示一个control group对某一个或者某几个cgroups子系统的资源限制。cgroup结构体可以组成一棵树,每一颗cgroup结构体组成的的树称为cgroup层级结构。cgroups层级结构可以attach一个或几个cgroups子系统,当前层级结构可以对其attach的cgroups子系统进行资源限制。每一个cgroups子系统只能被attach到一个cpu层级结构中
上图表示两个cgroups层级结构,每一个层级结构中是一颗树形结构,树的每一个节点是一个cgroups结构体(比如cpu_cgrp,memory_cgrp)。第一个cgroups层级结构attach了cpu子系统和cpuacct子系统,当前
cgroups层级结构中的cgroups层级结构中的cgroup结构体就可以对cpu资源进进行限制,并且对进程的cpu使用情况进行统计。
第二个cgroups层级结构中attach了memory子系统,当前cgroups层级结构中的cgroup结构体就可以对memory的资源进行限制。在每一个cgroups层级结构中,每一个节点(cgroup结构体)可以设置对资源不同的限制权重。比如上图中cgrp1组中的进程可以使用60%cpu时间片,而cgrp2组中的进程可以使用20%的cpu时间片。
cgroup层级关系显示,CPU和Memory两个子系统有自己独立的层级系统而又通过Task group取得关联关系
相互关系:
每次在系统中创建新层级时,该系统中所有任务都是那个层级默认cgroup(root cgroup,此cgoup在创建层级时自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员;
- 同一个hierarchy可以附加到一个或者多个subsystem
- 一个subsystem可以附加到多个hierarchy,当且仅当这个hierarchy只有这一个subsystem,如下图,hierarchy B已经有了一个subsystem Memory,所以hierarchy不能attach到CPU这个subsystem中
- 同一个task不能属于同一个hierarchy的不同的cgroup:
- fork出的子进程在初始化状态与其父进程处于同一个cgroup。进程(task)在fork出自身时创建子任务(child task)默认与原task在同一个cgroup,但之后这个子任务可以被移动到其它cgroup中去,可以理解为这个子任务是一个独立的进程:
五、cgroups与进程
在创建了cgroups层级结构中的节点(cgroup结构体)之后,可以把进程加入到某个节点的控制任务列表中,一个节点的控制列表中的所有进程都会受到当前节点的资源限制、同时一个进程也可以被加入到不同的cgroups层级结构的节点中,因为不同的cgroups层级结构可以负责不同的系统资源。所以说进程和cgroup结构是一个多对多的关系。
上图从总体结构描述了进程与cgroups之间的关系。最下面的P代表一个进程。每个进程的描述符中有一个指针指向一个辅助的数据结构css_set(cgroup subsystem set)。指向某一个 css_set的进程会被加入到当前的css_set的进程链表中。一个进程只能隶属一个css_set,一个css_set可以包含多个进程,隶属于同一css_set的进程受同一个css_set所管理的资源限制。
“MXN Linkage”说明css_set通过辅助的数据结构可以与cgroups节点进行多对多的关联。但是cgroup实现不允许css_set同时关联同一个cgroup层级结构下的多个节点。这是因为cgroups对同一种资源不运行有多个限额配置。
一个ccs_set关联多个cgroups层级结构的节点时,表明需要对当前css_set下的进程进行多种资源控制。而一个cgroups节点关联多个css_set时,表面多个css_set下的进行列表受到同一份资源的相同限制。
六、cgroups文件系统
Linux使用多种数据结构在内核中实现了cgroups的配置,关联了进程和cgroups节点,那么Linux如何让用户态的进程使用到cgroups的功能呢?
Linux内核有一个很强大的模块VFS(Virtual File System)。VFS能够把具体文件系统的细节隐藏起来,给用户态进程提供一个统一的文件系统API接口。cgroups也是通过VFS把功能暴露给用户态,cgroups与VFS衔接部分称为cgroups文件系统。
VFS:
VFS是一个内核抽象层,能够隐藏具体文件系统实现细节,从而给用户态提供一整套统一的API接口。VFS使用了一种通用文件系统的设计,具体的文件系统只要实现VFS的设计接口,就能够注册到VFS中,从而使内核可以读写这种文件系统。这很像面向对象设计中抽象类和子类之间的关系,抽象类负责对外接口的设计,子类负责具体的实现。其实,VFS本身就是用c语言实现的一套面向对象的接口。
VFS通用文件模型中包含以下四种元数据结构:
1. 超级块对象(superblock object) ,用于存放已经注册的文件系统信息。比如ext2,ext3等这些基础的磁盘文件系统,还用于读写socket的socket文件系统,以及当前用于读写cgroups文件系统等。
2. 索引节点对象(inode object),用于存放具体文件的信息。对于一般的磁盘文件系统而言,inode节点中一般会存放文件在硬盘中的存储块信息;对于socket文件系统,inode会存放socket的相关属性,而对于cgoups这样的特殊文件系统,inode会存放与cgroup节点相关的属性信息。这里比较重要的一部分叫做inode_operations的结构体,这个结构体定义了在具体文件系统中创建文件,删除文件等具体操作。
3. 文件对象(file object),一个文件对象表示一个进程打开的一个文件,文件对象是存放在进程文件描述符表里面的。同样这个文件中比较重要的部分是file_operations的结构体,这个结构体描述了具体的文件系统读写实现。当进程在某一个文件描述符上调用读写操作时,实际调用的时file_operations中定义的方法。对于普通的磁盘文件系统,file_operations中定义的就是普通块设备读写操作;对于socket文件系统,file_operations中定义的就是socket对应的send/recv等操作;而对于cgroups这样特殊的文件系统,file_operations中定义的就是操作cgroup结构体等具体实现。
4. 目录项对象(dentry object):在每个文件系统中,内核在查找一个路径的文件时,会为内核路径上的每一个分量都生成一个目录项对象,通过目录项对象找到对应的indode对象,目录项对象一般会被缓存,从而提供内核查找速度。
基于VFS实现的文件系统,都必须实现VFS通用文件模型定义这些对象,并实现这些对象中定义的部分函数。cgroup文件系统也不例外:
static struct file_system_type cgroup_fs_type = {
.name = "cgroup",
.mount = cgroup_mount, //安装cgroup文件系统要执行的函数
.kill_sb = cgroup_kill_sb, //卸载cgroup文件系统要执行的函数
}
每次把一个cgroups子系统安装到某个转载点时,cgroup_mount方法都会被调用,这个方法生成一个cgroup_root(cgroup层级结构的根)并封装成超级块对象。
cgroups超级块对象定义的操作:
static file_system_type cgroup_fs_type = {
.statfs = simple_statfs,
.drop_inode = generic_delelte_inode,
.show_option = cgroup_show_options,
.remount_fd = cgroup_remount,
}
cgroups文件系统对inode对象和file对象定义的特殊实现:
static const struct inode_operations cgroup_dir_inode_operations = {
.lookup = cgroup_lookup,
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
.rename = cgroup_rename,
};
static const struct file_operations cgroup_file_operations = {
.read = cgroup_file_read,
.write = cgroup_file_write,
.llseek = generic_file_llseek,
.open = cgroup_file_open,
.release = cgroup_file_release,
};
cgroups通过实现VFS的通用文件系统模型,把cgroups层级结构的细节,隐藏在cgroups文件系统的这些实现函数中。从令一个方面说,用户在用户态对cgroups文件系统的操作,通过VFS转化为对cgroups层级结构的维护。通过这样的方式,内核把cgroups的功能暴露给用户态进程。
七、cgroups使用方法
#################cgroups文件系统挂载###########################
Linux用户使用mount命令挂载cgroup文件系统,
mount -t cgroup -o subsystems name /cgroup/name #其中subsystems表示要挂载的cgroups子系统, /cgroup/name表示挂载点,这条命令同时在内核中创建了一个cgroups层级结构
比如挂载cpu_set,cpu, cpuacct,memory 4个subsystem到cgroup/cpu_and_mem目录下,
mount -t cgroup -o remount, cpu,cpuset, cpu_acct,memory cpu_and mem /cgroup/cup_and_mem
在centos下,使用yum install libcgroup安装了cgroups模块之后,在/etc/cgfong.conf文件中自动生成cgroups子系统的挂载点:
mount {
cpuset = /cgroup/cpuset;
cpu = /cgroup/cpu;
cpuacct = /cgroup/cpuacct;
memory = /cgroup/memory;
devices = /cgroup/devices;
freezer = /cgroup/freezer;
net_cls = /cgroup/net_cls;
blkio = /cgroup/blkio;
}
上面的每一条配置都等于展开的mount命令,例如
mount -t cgroup -o cpuset cpuset /cgroup/cpuset #这样系统启动之后会自动把这些子系统挂载到相应的挂载点
#########子节点和进程############
挂载某个cgroups子系统到挂载点后,就可以通过在挂载点下面建立文件夹或者使用cgcreate命令创建cgroups层级结构中的节点,比如通过命令
cgcreate -t sankkuai:sankuai -g cpu: test #就可以在cpu子系统下面建立一个名为test节点
[root@idx cpu]# ls
cgroup.event_control cgroup.procs cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us cpu.rt_runtime_us cpu.shares cpu.stat lxc notify_on_release release_agent tasks test
然后可以通过写入需要的值到test下面不同文件,来配置需要限制的资源。每个子系统下面都可以进行多种不同的配置,需要配置的参数各不相同,详细的参数配置参考cgroups手册。可以使用cgset命令设置cgroups子系统参数,格式为
cgset -r parameter=value path_to_cgroup
当删除某一个cgroup节点时候,可以使用cgdelete命令,比如要删除test节点,
cgdelete -r cpu:test #删除test节点
把进程加入到cgroups子节点有很多方法,可以把pid写入到子节点下面的task文件中,也可以通过cgclassify添加进程
cgclassify -g subsystem:path_to_cgroup pidlist
也可以直接使用cgexec在某个cgroups下启动进程
cgexec -g subsystem:path_to_cgoup command aguments
八、cgroups实践
Docker在实现不同的Container之间资源隔离和控制的时候,可以创建复杂的cgroups节点和配置文件完成,对于同一个Container中的进程,可以把这些进程的PID添加到同一组cgroups子节点中达到对这些进程进行同样的资源限制。
九、cgroups优点
1. 在cgroups引入内核之前,想要完成对某一个进程CPU使用率进行限制,只能通过nice命令调整进程的优先级,或者cpulimit命令限制进程使用进程的CPU使用率,缺点是无法限制一个进程组的资源使用限制,也无法完成Docker或者其它云平台所需的这一类轻型容器资源限制。
2. 在cgroups之前,想要完成一个或者一组进程的物理内存使用率的限制,几乎不可能完成。使用cgroups提供的功能,可以轻易的限制限制系统内某一组物理内存占用率、对于网络包,设备访问或者io资源控制,cgroups同样提供了之前无法完成的精细化控制。
今天的文章Cgroup概述_cg概念设计师分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/70235.html