什么是Cgroups?
cgroups,其名称源自控制组群(control groups)的简写,是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。最初由google的工程师提出,现在已经整合进Linux内核。
cgroup的控制,统计,都是以整个cgroup来计算,即cgroup里面进程的资源使用总合。
Cgroups的功能:
资源限制:组可以被设置不超过设定的内存限制;这也包括虚拟内存。
优先化:一些组可能会得到大量的CPU或磁盘输入输出通量。
报告:用来衡量系统确实把多少资源用到适合的目的上。
分离:为组分离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件。
控制:冻结组或检查点和重启动。
Cgroups相关概念:
在cgroups中,所有和cgroups的交互都是通过cgroup的文件系统。cgroup通过挂载层级来建立和用户层交互的通道。
先来尝试一下挂载。
1 |
#mount -t cgroup -o 子系统 层级名 挂载点 |
2 |
#比如 |
3 |
mount -t cgroup -o cpu,cpuset,memory cpu_and_mem /cgroup/cpu_and_mem |
4 |
#这条指令把cpu,cpuset,memory附加到cpu_and_mem层级,然后挂载到 /cgroup/cpu_and_mem |
5 |
#注意要root权限执行。 |
6 |
#执行指令后,我们会发现/cgroup/cpu_and_mem多出了很多奇怪的文件。 |
这些文件后面再说,先介绍概念。
下面在介绍概念的同时,介绍这些概念在cgroup文件系统中的表现。
1.任务(task):
说明:在cgroups中,任务就是系统的一个进程。
表现:在文件系统中,有一个名为tasks文件,里保存着进程的PID。所有移动进程的操作都是通过写入PID到相应的tasks文件完成。
2.层级(hierarchy):
说明:控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。
表现:可以看成挂载到挂载点的块。(为什么不说是挂载点呢?因为事实上卸载掉cgroup的文件系统后,cgroup层级依然存在。这是很多cgroup错误的原因。)
3.子系统(subsytem):
说明:一个子系统就是一个资源控制器,比如cpu子系统就是控制cpu时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。事实上子系统比cgroup更早出现。
表现:子系统是附加到层级上的,挂载上去之后出现相应的控制文件。
4.控制族群(control group):
说明:控制族群就是一组按照某种标准划分的进程。Cgroups中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用cgroups以控制族群为单位分配的资源,同时受到cgroups以控制族群为单位设定的限制。
表现:挂载点就可以认为是一个特殊的cgroup,称之为root cgroup,在里面创建文件夹就对应创建一个cgroup。
Cgroups的规则:
1.一个层级可以附加多个子系统。
解释:mount的-o后面跟cpu,cpuset,memory等多个子系统。
注意:挂载了cpu之后,再往挂载点挂载memory不是附加多个子系统(区别层级和挂载点),这是挂载的覆盖。
2.一个子系统最多只能附加到一个层级。
解释:当我们把cpu,cpuset附加到一个层级A,挂载后。我们不能创建cpu,memory或者是cpu或者cpu,cpuset,memory这样的层级。
注意:有人会发现,可以再mount一个cpu,cpuse到别的目录下。因为这没有创建新的层级,只是把层级再挂载到另一个目录。可以发现,两个挂载点中的文件是一样的。
3.一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级。
解释:准确的说是任务必须在不同的子系统。这是必然的的,因为每个子系统的实现都是在内核中,即使没有挂载cgroup层级,它们的数据结构都存在(子系统就好像进程的各个资源维度),所以每个进程就已经和各个子系统挂钩了。层级可以认为是子系统的展现。
反过来理解,是子系统绑定到进程,而不是进程绑定到层级。cgroup起到的是对进程分组的作用。
4.进程创建的继承
解释:系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员,它总是继承其父任务的cgroup。可以认为是fork时,把子系统的控制结构也拷贝了一份。
5.层级的默认 cgroup(root cgroup)
每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup ,此cgroup在创建层级时自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员。此时它的tasks中有所有的进程PID。
可以认为这是一个默认分组,root cgroup的设置就是默认配置,里面的子cgroup是自定义的分组,里面的配置在创建时继承了父cgroup的设置。新建的子cgroup中tasks为空,直到你移入进程。
总结:
注意:cgroup的继承指的是配置的继承,在创建新的子cgroup时,所有配置都和父cgroup相同。
我踩过的坑:我一直以为cgroup有树状的限制,比如cgorup A限制了内存最大100M,作为A的子cgroup B,限制80M,就认为,cgroup B的80M是100M的一部分。A下的进程最少用20M的内存。事实上,这个层级关系是有参数控制的。进程从root cgroup移入自己的子cgroup时,这个进程的统计数据就不累计到root cgroup了。
一个例外:memory子系统有一个memory.use_hierarchy,这是个布尔开关,默认为 0。此时不同层次间的资源限制和使用值都是独立的。当设为 1 时,子控制组进程的内存占用也会计入父控制组,并上溯到所有 memory.use_hierarchy = 1 的祖先控制组。目前只有memory子系统有此功能。
可以认为,对于进程来说每个cgroup都是处于同一个层次,包括root cgroup,不一样的只是cgroup的配置参数和划分在这个cgroup的进程。
转载请注明:旅途@KryptosX » 初探Cgroups(控制组群)