前言
Cgroup和namespace类似,也是将进程进程分组,但是目的与namespace不一样,namespace是为了隔离进程组之前的资源,而Cgroup是为了对一组进程进行统一的资源监控和限制。
Cgroup的组成
subsystem
一个subsystem就是一个内核模块(例如:图中的cpu,memory).它被关联到一颗Cgroup树之后,它就会对树的每个节点(进程组) 调度和限制资源,监控,及观察进程组的状态.
目前Linux支持12中system,比如限制CPU的使用时间,限制使用内存,统计CPU使用情况,冻结和恢复一组进程等。
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 |
Hierachy
cgroup结构体可以组成一棵树,每一颗cgroup结构体组成的的树称为cgroup层级结构(hierarchy)
当前层级结构可以对其子的cgroups进行资源限制, 如图所示
- cgroup1 中限制了使用 cpu 及 内存资源,它将控制子节点的 CPU 周期和内存分配(即,限制 cgroup2、cgroup3、cgroup4 中的cpu及内存资源分配)。
- cgroup2 中启用了内存限制,但是没有启用cpu的资源限制,这就导致了 cgroup3 和 cgroup4 的内存资源受 cgroup2中的 mem 设置内容的限制;
- cgroup3 和 cgroup4 会自由竞争在 cgroup1 的 cpu 资源限制范围内的 cpu 资源。
也可以明显的看出 cgroup 资源是自上而下分布约束的。只有当资源已经从上游 cgroup 节点分发给下游时,下游的 cgroup 才能进一步分发约束资源。
Task
任务即系统的一个进程。一个进程可以加入到某个cgroups,也可以从一个cgroups迁移到另一个cgroups。一个进程组的进程可以使用cgroups为单位分配资源,同时受到cgroups为单位设定限制。
三者关系
- 同一个task不能属于同一个hierarchy的不同的cgroup
- 同一个hierarchy可以附加到一个或者多个subsystem
- 一个subsystem可以附加到多个hierarchy,当且仅当这个hierarchy只有这一个subsystem。
- fork出的子进程在初始化状态与其父进程处于同一个cgroup。
2,3 可以理解为,当hierarchy有能力管理多个资源的时候,让别的hierarchy,分担你其中一资源。当仅仅当你一个资源的管理不过来的时候可以分担
实操
要想使用cgroup,要先通过两种方式创建
- 在/sys/fs/cgroup目录中的任何subsystem中创建子目录,并把任务的PID添加到tasks文件中,该文件会在创建子目录后立即自动创
- 通过libcgroup库创建、删除和管理cgroups
这里我们使用第一种。
- 现在我们前往memory子目录
cd memory
- 创建cgroup_test_group目录
mkdir cgroup_test_group
- 在创建完cgroup_test_group文件夹之后,下面的文件会自动创建:
/sys/fs/cgroup/memory/cgroup_test_group$ ls -l
total 0
-rw-r--r-- 1 root root 0 May 7 01:00 cgroup.clone_children
--w--w--w- 1 root root 0 May 7 01:00 cgroup.event_control
-rw-r--r-- 1 root root 0 May 7 01:00 cgroup.procs
-r--r--r-- 1 root root 0 May 7 01:00 memory.stat
-rw-r--r-- 1 root root 0 May 7 01:00 memory.swappiness
-rw-r--r-- 1 root root 0 May 7 01:18 memory.limit_in_bytes
-r--r--r-- 1 root root 0 May 7 01:00 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 May 7 01:00 memory.use_hierarchy
-rw-r--r-- 1 root root 0 May 7 01:00 notify_on_release
-rw-r--r-- 1 root root 0 May 7 01:00 tasks
- 设置最大内内存
echo 1048576 > memory.limit_in_bytes
- 关闭虚拟内存swap
echo 0 > memory.swappiness
- 编写java程序
public class Demo {
public static void main(String[] args) throws InterruptedException {
byte[][] a = new byte[10000][];
for (int i = 0; i < 10000; i++) {
a[i] = new byte[1024 * 5];
System.out.println("创建了" + (i+1) * 5 + "K" );
Thread.sleep(300);
}
}
}
- 运行java并将pid加入task
echo ${pid} > tasks
发现创建到645K就被kill了,因为Java虚拟机本生运行要内存
主要参考
《Cgroup概述》
《memory cgroup》