cgroups I - usage
0x00 what is cgroup?
cgroups 是 Linux 内核的一个功能,用来限制,控制与分离一个进程组群的资源(如 CPU, 内存,网络,磁盘输入输出等).
0x01 The begin of cgroups
这个项目最早是由 Google 的工程师在 2006 年发起 (主要是 Paul Menage 和 Rohit Seth), 最早的名称为进程容器 (process containers). 在 2007 年时,因为在 Linux 内核中,容器 (container) 这个名词有许多不同的意义,为避免混乱,被重命名为 cgroup, 并且被合并到 2.6.24 版的内核中去 [^wiki].
0x02 feature
cgroup 的一个设计目标是为不同的应用情况提供统一的接口,从控制单一进程 (像 nice) 到操作系统层虚拟化 (像 opeNVZ,Linux-VServer,LXC).
cgroups 提供 [^access]:
- 资源限制:组可以被设置不超过设定的内存限制;这也包括虚拟内存。
- 优先化:一些组可能会得到大量的 CPU[5] 或磁盘输入输出通量。
- 报告:用来衡量系统确实把多少资源用到适合的目的上。
- 分离:为组分离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件。
- 控制:冻结组或检查点和重启动。
0x03 the position of cgroups in kernel
可以在下图看到其所在:
0x10 The struct of cgroups
0x11 term
- *任务 (Tasks)*:就是系统的一个进程。
- *控制组 (Control Group)*:一组按照某种标准划分的进程,比如官方文档中的 Professor 和 Student, 或是 WWW 和 System 之类的,其表示了某进程组.Cgroups 中的资源控制都是以控制组为单位实现。一个进程可以加入到某个控制组。而资源的限制是定义在这个组上。简单点说,cgroup 的呈现就是一个目录带一系列的可配置文件。
- *层级 (Hierarchy)*:控制组可以组织成 hierarchical 的形式,既一颗控制组的树 (目录结构). 控制组树上的子节点继承父结点的属性。简单点说,hierarchy 就是在一个或多个子系统上的 cgroups 目录树。
- *子系统 (Subsystem)*:一个子系统就是一个资源控制器,比如 CPU 子系统就是控制 CPU 时间分配的一个控制器。子系统必须附加到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制.Cgroup 的子系统可以有很多,也在不断增加中。
0x12 resource mangement
引用这个图片,尝试解释一下 cgroup 的资源划分的结构。不同颜色代表不同group
对资源的划分,不过这个设计存在一些缺陷已经遭到Tejun Heo
的 吐槽, 某个任务归类方式的多样性导致了多个Hierarchy
的正交,导致了进程管理的复杂。多个子系统的之间的交叉使用导致了管理的复杂,不过在一些 cgroup 套件里面使用配置文件转移一部这个问题的复杂度。
0x13 subsystem
- blkio — 这个子系统为块设备设定输入 / 输出限制,比如物理设备(磁盘,固态硬盘,USB 等等).
- cpu — 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。
- cpuacct — 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。
- cpuset — 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
- devices — 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。
- freezer — 这个子系统挂起或者恢复 cgroup 中的任务。
- memory — 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成内存资源使用报告。
- net_cls — 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。
- net_prio — 这个子系统用来设计网络流量的优先级
- hugetlb — 这个子系统主要针对于 HugeTLB 系统进行限制,这是一个大页文件系统。
0x20 Base usage in CLI
0x21 确认系统
在使用systemd
的系统里面hierarchy
由其启动时自动创建,在rhel6
系列中需要yum install libcgroup
, 如果是Ubuntu
系列的话较新的版本是自带了。
查看 cgroup 文件系统的挂载:
1 | mount -t cgroup |
查看子系统:
1 | lssubsys |
0x22 使用案例 1
Linux 中把cgroups
实现成了文件系统,所以对文件系统里面的特定文件进行操作就可以完成对cgroup
的配置。
demo[^coolshell]:
1 | int main(void) |
配置:首先在某个子系统下面建立一个目录,其目录里面会自动创建与其相关的文件 (文件名表示其意义); 其次置具体参数到文件名; 然后把要限制的进程 PID 放入task
的文件。
1 | mkdir /sys/fs/cgroup/cpu/eleme |
配置前:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4434 root 25 5 4164 356 280 R 92.0 0.0 0:04.18 deadloop
配置后:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4434 root 25 5 4164 356 280 R 2.0 0.0 1:14.91 deadloop
0x23 使用案例 2
之所以单独记录了 netcls 的使用,是因为netcls
相当于cgroup
中其他的控制组使用起来不是很方便 (需要外部工具配合).
在 cgroup 中,通过 netcls 子系统使用识别符 (classid) 标记网络数据包,标记完成过后一般是以下两个操作。
- 可用流量控制器 (tc) 从不同的
cgroup
中关联不同的优先级到数据包,这个场景多数是用于QOS
相关。 - 也可以用
iptables
来对这些具有这些特征 (-m cgroup) 流量做一些具体的操作,这个操作幅度比QOS
的要大,根据iptables
的不同table
提供的-J
有很多动作可以做。
- Basic Queuing technology
在描述
Linux QOS
之前需要想象最基本的队列技术 - 普通队列 (FIFO), 而后对其有了点改进诞生了由 3 个队列一起工作 (pfifo), 由多个队列一起工作的 (Stochastic Fair Queuing) 和拿着令牌才能走包的 (token bucket filter)[^qdisc].
需要补充说明的是虽然 linux 也支持基于字节的队列技术bfifo
, 但是bfifo
在特性支持上要远逊色于pfifo
.接口默认队列技术的 pfifo_fast pfifo(基于 packet 的 fifo) 默认是使用三个队列,能提供基本的优先级功能。看上去公平的 sfq sfq 的公平是由 hash 与轮序算法保证的。更多信息 [这里](http://wiki.mikrotik.com/wiki/Manual:Queue#SFQ)拿着令牌才放行的 tbf
即使这样多数情况依然不够!
比如”A,B,C,D 四个服务,其中 A 是延迟敏感的视频会议,B 是吞吐量大的 bt 下载,C,D 普通的 web 流量”, 上面提供的这些功能或多或少只能满足一部分服务。这个时候一个层次化的划分队列被开发出来了,虽然 linux 也实现了其它的有类队列规则,但是他们远不如其中的 HTB(Hierarchical Token Bucket) 使用更加广泛 [^packet_flow].
htb 允许创建层次的队列结构与决定队列之间的关系 (父 - 子,子 - 子).
一般的使用步骤如下:
1: 匹配和标记流量:将流量分类待使用,利用包含一个或者多个匹配参数来选择数据包构成一个 class
2: 创建策略到标记的流量上:把具体的 class 放到特定的队列中并定义每个 class 携带的动作。
3: 附加策略到到特定接口:附加策略到全局接口 (全局进,全局出,全局进出), 特定接口或者父队列。
htb demo[^htb]:
1 | This line sets a HTB qdisc on the root of eth0, and it specifies that |
对前面的QOS
有了了解,加上在 2014 年netfilter
支持了cgroup
特性,用户态需要安装新的 iptables, 而后可以match
出cgroup
相关的流量,这个时候net_cls
才算能和netfilter
一起工作 [^net_cls_doc].
1 | !/bin/sh |
[^access]: redhat access
[^wiki]: wikipedia
[^coolshell]: coolshell
[^net_cls_doc]: cgroup net_cls doc
[^linux_tc]: Linux taffic control
[^linux_fw]: linux firewalls
[^packet_flow]: MikroTik RouterOS packet flow
[^qdisc]: classful qdiscs
[^htb]: HTB
[^example]: cgroup 使用范例