查看原文
其他

平凡:Docker底层的内核知识——cgroups

平凡 Linux内核之旅 2022-09-10

Linux内核之旅快来点击关注








作者简介

平凡,西安邮电大学在读研二学生,

积极乐观,在做好自己专业的同时也喜欢了解各方面的知识,包括会使用hadoop与tensorflow。也深入学习linux, 分析了许多如进程调度、文件系统的内核源码。对新技术也怀抱有很大的学习热情,目前专注于docker和kubernetes。




本来呢,

可以满足下大家的好奇心

给大家附一张作者的照片

但是

作者有点扭捏害羞了


于是小编我决定

给大家大概描述下我的这位师兄

(高能预警!前方灵魂画手出没)




哈哈哈我又来聊天气了

这次还是带着我平凡师兄

哦对了

我师兄声音也是很好听的



下方语音包,点击食用






我的上一篇博客Docker底层的内核知识——namespace讲解了内核中支持Docker作资源隔离的机制namespace。本篇文章主要讲述Docker背后内核的另一机制——cgourps。cgroups不仅可以用来限制被namespace隔离的资源,还可以为资源设置权重、计算使用量、操控任务启停等。






从Linux系统中看cgroups


 我们依然先从操作系统中直观的看一下cgroups是个什么东西

进入到sys/fs/cgroup/目录下,我们可以看到许多目录,如上图所见。 
这些如blkio、cpu、cpuacct等目录都是cgroups机制的子系统,子系统的概念一会再解释。简单来说,就是这些东西就是对cgroup做资源限制的。blkio负责为块设备设定输入/输出限制,比如物理驱动设备——磁盘。cpu使用调度程序控制任务对cpu的使用,cpuacct自动生成cgroup中任务对CPU资源使用情况的报告。 
而正如我们所见,为了让cgroups便于用户理解和使用,也为了用精简的内核代码为cgroup提供熟悉的权限和命名空间管理,内核开发者们按照Linux虚拟文件系统转换器接口实现了一套名为cgroup的文件系统,非常巧妙地用来表示cgroups的层级概念,把各个子系统的实现都封装到文件系统的各项操作中。那么,我们就可以像操作文件一样对cgroups的层级进行浏览和操作管理。除了cgroup文件系统以外,内核没有为cgroups的访问和操作添加任何系统调用,这点与namespace不同,namespace都是通过系统调用来进行操作和管理的。



cgroups的由来

在操作系统中感受了cgroups,下面我们来看看cgroups的由来。 
cgroups是由Google的工程师于2006年提出的,最初名为process container。为什么叫这个名字呢?因为刚开始有cgroups的概念时,namespace其实是cgroups的一个子系统,也就是说,cgroups当时还具有资源隔离的功能。不过后来的发展将namespace独立出去了。另外,由于container具有多重含义容易引起误解,就在2007年更名为control groups,并整合进Linux内核,顾名思义就是把任务放到一个组里面加以控制,这个组就是cgroup。



cgroups的官方定义

在这里给出最严谨的官方定义: 
cgroups是Linux内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。


关于cgroups的术语

相信大家经常会听人说cgroups或者cgroup。就比如我文章前面,一会提到cgroups,一会提到cgroup,这两个术语之间有什么区别呢?接下来列举关于cgroups的几个术语加以理解: 
cgroups:cgroups是Linux内核中的一个机制,我们用它来作容器资源的限制等功能。 
cgroup:cgroup中文叫做控制组。它是cgroups实现资源控制的一个基本单位。cgroup表示按某种资源控制标准划分而成的一个任务组。它其中包含有一个或多个任务。 
task:前面介绍cgroup时提到的任务就是task。任务表示系统的一个进程或线程。之所以把进程和线程统称为任务,是因为内核本身的调度和管理并没有对进程和线程做区分,只根据clone创建时传入参数的不同从概念上区别进程和线程,所以cgroups中简化称之。 
subsystem:cgroups中的子系统。一个子系统就是一个资源调度控制器。比如前面一开始让大家看的cpu、memory、blkio、cpuacct等都是子系统。 
hierarchy:中文叫做层级。层级由一系列cgroup以一个树状结构排列而成。每个层级通过绑定对应的子系统进行资源控制。前面一开始看到的目录就是子系统,而这些子系统就挂载着层级。一个层级内创建一个目录就类似于fork一个cgroup,这个cgroup继承了父cgroup的配置属性。当然,后面可以进行配置属性的修改。 
语言叙述太苍白,请看实际操作: 
我们进入cpu子系统的层级下,创建一个目录cgroup1,这个cgroup1就是一个新创建的cgroup控制组,我们可以看下cgroup1中的内容。 

可以看到cgroup1目录下直接有这么多文件,且和cpu目录下本来存在的文件相同。实际上就是cgroup1继承了根cgroup的配置属性。这个根cgroup是新建层级之时就有的。我们分别看一下两个目录下cpu.shares的值,会发现它们都是1024。 


cgroups的作用

我们上面说完了cgroups的一些术语。以后对cgroups的术语就不用傻傻分不清楚了。我们常说cgroups是做资源限制的,而cgroups的功能其实不单单是做资源限制的。接下来我们看一下cgroups具体能干些什么。 
cgroups为我们提供了四项功能: 
资源限制:cgroups可以对任务使用的资源总额进行限制。如cpu的使用,memory的使用。 
优先级分配:通过分配的CPU时间片数量及磁盘IO带宽大小,实际上就相当于控制了任务运行的优先级。 
资源统计:cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等信息,该功能可以用于资源使用的计费。 
任务控制:cgroups可以对任务执行挂起、恢复等操作。


子系统简介

前面已经解释过了什么是子系统。这里对子系统再进行详细的讲述,因为一个子系统就是一个资源控制器,每个子系统都独立地控制一种资源。 
这是我们一开始就看到的图片,接下来我们挑几个重要的子系统再进行解释: 
blkio:可以为块设备设定输入/输出限制,比如物理驱动设备。 
cpu:使用调度程序控制任务对CPU的使用。 
cpuacct:自动生成cgroup中任务对CPU资源使用情况的报告。实际就是记录CPU的使用情况。 
cpuset:可以为cgroup中的任务分配独立的CPU和内存。当然,分配独立的CPU的前提是节点是多处理器的。 
devices:可以开启或关闭cgroup中任务对设备的访问。 
freezer:可以挂起或恢复cgroup中的任务。这就是cgroups的任务控制功能。 
memory:可以设定cgroup中任务对内存使用量的限定,并且自动生成这些任务对内存资源使用情况的报告。 
perf_event:使用后使cgroup中的任务可以进行统一的性能测试。 
net_cls:Docker没有直接使用它,它通过使用等级识别符标记网络数据包,从而允许Linux流量控制程序识别从具体cgroup中生成的数据包。 
pids:用来限制cgroup中任务的数量。 


cproups超出限额的后果

我们都知道cgroup作为一个资源控制的基本单位。那么,当cgroup使用的资源超出了分配的限额会有什么后果呢? 
以内存为例,当进程所需的内存超过了它所属的cgroup最大限额时,如果Linux设置了OOM,那么进程会收到OOM信号并结束;否则进程就会被挂起,进入睡眠状态,直到cgroup中其他进程释放了足够的内存资源为止。Docker中是默认开启OOM的。其他子系统的资源限制与此类似。



总结

cgroups相比于namespace解释起来比较复杂,因为要做实际的演示比较难。最直观的了解cgroups就是通过看cgroup文件系统来感受它。(cd
/sys/fs/cgroup/
)除了cgroup文件系统以外,内核没有为cgroups的访问和操作添加任何系统调用。虽然操作方式不同,cgroups和namespace一个做资源控制,一个做资源隔离。共同成为Docker背后的内核支持机制。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存