1.背景上一篇《浅谈Cgroups》介绍了cgroupv1,但是由于k8s目前使用cephfs进行数据存储,多租户使用时,需要限制IO。由于cgroupv1中memcg和blkio不配合,bufferio的throttle没有实现。而cgroupv1在内核中的实现一直比较混乱。主要原因是为了提供灵活性,cgroup允许进程属于多个层次结构的不同组。但实际上,多个层次结构并没有多大用处,因为一个控制器(controller)只能属于一个层次结构。所以在实际使用中,通常每一层级都有一个控制器。这种多层次结构除了增加代码的复杂性并使其难以理解外,并没有多大用处。一方面,跟踪流程的所有控制器变得复杂;另一方面,各个controller很难协同工作(因为controller可能属于不同的hierarchy,所以从3.16开始,kernel开始转向单一level(unifiedhierarchy)。并实现了Bufferiolimitation2.Cgroupsv2的变化由于Cgroupsv1的各种问题,Cgroupsv2将多层次的方式改为统一层次,将所有controller挂载到一个统一的层次中,当前内核没有去掉Cgroupsv1版本允许Cgroupsv1和v2共存,但是同一个controller不能同时挂载到这两个不同的Cgroup版本。以下是Cgroupsv2的五项改进:Cgroupsv2中的所有控制器将挂载在一个统一的层次结构下,而不是v1中允许不同的控制器挂载到不同的层次结构,Proess只能绑定到cgroups的根目录(“/”)directory和cgroup目录树中的叶节点指定哪些控制器可以被cgroup.controllers和cgroup.subtree_control使用。去除了v1版本中的task文件和cpusetcontroller中的cgroup.clone_children文件改进了空时通知机制,使用cgroup.events文件进行通知3.统一层次结构,允许不同的controller挂载到Cgroupsv1中的不同层次结构。虽然很灵活,但这种方法对于使用者来说其实是不必要的。因此,在Cgroupsv2版本中,所有的controller都被挂载到一个hierarchy中。您可以使用以下命令将Cgroupsv2挂载到文件系统,所有可用的控制器将自动挂载。mount-tcgroup2none$MOUNT_POINT控制器不能同时用于Cgroupsv1和v2。如果你想在Cgroupsv2中使用一个已经被Cgroupsv1使用过的控制器,你需要先从Cgroupsv1中卸载它。需要注意的是,系统启动时,systemd默认使用Cgroupsv1,并将可用的controller挂载到/sys/fs/cgroup。如果想在系统启动时关闭Cgroupsv1,可以修改/etc/default/grub文件中的内核参数,添加GRUB_CMDLINE_LINUX_DEFAULT="cgroup_no_v1=all"。(all的意思是关闭所有的控制器,如果要关闭指定的控制器,将all替换成你需要的控制器名,并用逗号隔开)。这样,你就可以在Cgroupsv2中使用你想要的控制器了。4.controllers目前的cgroupv2支持以下控制器:io(sinceLinux4.5)memory(sinceLinux4.5)pids(sinceLinux4.5)perf_event(sinceLinux4.11)rdma(sinceLinux4.11)cpu(sinceLinux4.15)5.子树控制层次结构下的每个Cgroup都会包含以下两个文件cgroup.controllers:这是一个只读文件。包含Cgroup下所有可用的控制器。cgroup.subtree_control:这个文件包含了Cgroup下已经打开的controller。cgroup.subtree_control中包含的控制器是cgroup.controllers文件的控制器的子集。cgroup.subtree_control文件的内容格式如下。控制器之间使用空格,前面用“+”表示激活,用“-”表示禁用。例如下面的例子:echo'+pids-memory'>x/y/cgroup.subtree_controlCgroupsv2的具体组织结构如下图所示:6.“无内部进程”规则与Cgroupsv1不同.Cgroupsv2只能绑定固定在叶节点上的进程。因此,进程不能绑定到任何已打开的控制器的任何子组。7、在Cgroupsv2的实现中,cgroup.events文件也优化了组为空时的通知机制。使用release_agent和notify_on_release的Cgroupsv1在v2中被移除。而是使用cgroup.events文件。这是一个只读文件,每行一个键值对,键和值之间用空格分隔。目前这个文件只有一个key,populated,对应的值为0。0表示cgroup中没有进程,1表示cgroup中有进程。8.cgroup.stat文件Cgroupsv2层次结构下的每个组都会包含一个只读文件cgroup.stat。它的内容也是key-value的形式。目前这个文件包含以下两个key:nr_descendants:表示cgroup中存活子组的数量nr_dying_descendants:表示cgroup中死亡cgroup的数量9.后代Cgroup的数量在Cgroupsv2层级中是有限制的,包含两个供查看并为Cgroups下的后代Cgroup数量设置限制文件:cgroup.max.depth(sinceLinux4.14):该文件定义了子cgroup的最大深度。0表示不能创建cgroup。如果尝试创建cgroup,会报EAGAIN错误;max表示没有限制,默认值为max。cgroup.max.descendants(自Linux4.14起):当前可以创建的活动cgroup目录的最大数量。默认值“max”表示无限制。如果超出限制,则返回EAGAIN。【本文为栏目组织360Tech、微信公众号《360Tech(id:qihoo_tech)》原创文章】点此阅读更多本作者好文
