前言
Linux Cgroups提供了对一组进程及将来子进程的资源限制、控制和统计的能力,这些资源包括CPU、内存、存储、网络等.
概念
tasks: 在cgroups中,任务就是系统的一个进程.
cgroup(control group): 一组按照某种标准划分的进程.
hierarchy: 把一组cgroup串成一个树状的结构, 可以做到继承. 比如系统对一组定时的任务进程通过cgroup1限制了CPU的使用率,然后其中有一个定时dump日志的进程还需要限制磁盘IO ,为了避免限制了磁盘IO之后影响到其他进程,就可以创建cgroup2,使其继承于cgroup1井限制磁盘的IO,这样cgroup2 便继承了cgroup1 中对CPU 使用率的限制,并且增加了磁盘IO的限制而不影响到cgroup1 中的其他进程.
subsystem: 一个子系统就是一个资源控制器.
他们直接的相互关系如下:
1. 每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认cgroup(称之为root cgroup,此cgroup在创建层级时自动创建,后面在该层级中创建的cgroup都是此 cgroup 的后代)的初始成员.
2. 一个子系统最多只能附加到一个层级.
3. 一个层级可以附加多个子系统.
4. 一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级.
5. 系统中的进程创建子进程时,该子任务自动成为其父进程所在cgroup 的成员。然后可根据需要将该子任务移动到不同的cgroup中,但开始时它总是继承其父任务的cgroup.
如下所示:
hierarchy-subsystem-cgroup-task.png
CPU 和 Memory 两个子系统有自己独立的层级系统, 而又通过 Task 取得关联关系, 该task既有CPU的限制又有Memory的限制.
本机支持的subsystem
root@nicktming:~# cd /sys/fs/cgroup/
root@nicktming:/sys/fs/cgroup# ls
systemd
root@nicktming:/sys/fs/cgroup# apt-get install cgroup-bin
root@nicktming:/sys/fs/cgroup# lssubsys -a
cpuset
cpu
cpuacct
memory
devices
freezer
blkio
perf_event
hugetlb
root@nicktming:/sys/fs/cgroup# ls
blkio cpu cpuacct cpuset devices freezer hugetlb memory perf_event systemd
cgroup
root@nicktming:~# mkdir cgroup && cd cgroup
root@nicktming:~/cgroup# mkdir demo
root@nicktming:~/cgroup# mount -t cgroup -o none,name=demo demo ./demo
root@nicktming:~/cgroup# ls ./demo
cgroup.clone_children cgroup.event_control cgroup.procs cgroup.sane_behavior notify_on_release release_agent tasks
root@nicktming:~/cgroup# wc -l ./demo/cgroup.procs
80 ./demo/cgroup.procs
root@nicktming:~/cgroup# wc -l ./demo/tasks
95 ./demo/tasks
cgroup.clone_children: cpuset 的subsystem 会读取这个配置文件,如果这个值是1 (默认是0 ), 子cgroup 才会继承父cgroup 的cpuset 的配置.
cgroup.procs: 树中当前节点cgroup中的进程组ID ,现在的位置是在根节点,这个文件中会有现在系统中所有进程组的ID.
tasks: 标识该cgroup下面的进程ID,如果把一个进程ID写到tasks文件中,便会将相应的进程加入到这个cgroup中.
创建和删除子cgroup
root@nicktming:~/cgroup# cd demo/
root@nicktming:~/cgroup/demo# mkdir cgroup1
root@nicktming:~/cgroup/demo# ls cgroup1/
cgroup.clone_children cgroup.event_control cgroup.procs notify_on_release tasks
root@nicktming:~/cgroup/demo# mkdir cgroup2
root@nicktming:~/cgroup/demo# tree
.
|-- cgroup1
| |-- cgroup.clone_children
| |-- cgroup.event_control
| |-- cgroup.procs
| |-- notify_on_release
| `-- tasks
|-- cgroup2
| |-- cgroup.clone_children
| |-- cgroup.event_control
| |-- cgroup.procs
| |-- notify_on_release
| `-- tasks
|-- cgroup.clone_children
|-- cgroup.event_control
|-- cgroup.procs
|-- cgroup.sane_behavior
|-- notify_on_release
|-- release_agent
`-- tasks
root@nicktming:~/cgroup/demo# sh -c "echo $$ > cgroup1/tasks"
root@nicktming:~/cgroup/demo# cat cgroup1/tasks
11749
14172
root@nicktming:~/cgroup/demo# cat cgroup2/tasks
// 删除子cgroup 直接删除其文件夹即可
root@nicktming:~/cgroup/demo# rmdir cgroup2
// 如果子cgroup中tasks中有进程的时候删除不了, 必须把进程移到别的cgroup中才可以删除
root@nicktming:~/cgroup/demo# rmdir cgroup1
rmdir: failed to remove ‘cgroup1’: Device or resource busy
// 将该进程从cgroup1移到demo cgroup中
root@nicktming:~/cgroup/demo# sh -c "echo 11749 > tasks"
root@nicktming:~/cgroup/demo# cat cgroup1/tasks
root@nicktming:~/cgroup/demo# rmdir cgroup1
root@nicktming:~/cgroup/demo# tree
.
|-- cgroup.clone_children
|-- cgroup.event_control
|-- cgroup.procs
|-- cgroup.sane_behavior
|-- notify_on_release
|-- release_agent
`-- tasks
subsystem
memory
可以限制cgroup中所有进程所能使用的物理内存总量等等.
root@nicktming:/sys/fs/cgroup/memory# ls
cgroup.clone_children memory.kmem.failcnt memory.kmem.tcp.max_usage_in_bytes memory.numa_stat memory.usage_in_bytes
cgroup.event_control memory.kmem.limit_in_bytes memory.kmem.tcp.usage_in_bytes memory.oom_control memory.use_hierarchy
cgroup.procs memory.kmem.max_usage_in_bytes memory.kmem.usage_in_bytes memory.pressure_level notify_on_release
cgroup.sane_behavior memory.kmem.slabinfo memory.limit_in_bytes memory.soft_limit_in_bytes release_agent
memory.failcnt memory.kmem.tcp.failcnt memory.max_usage_in_bytes memory.stat tasks
memory.force_empty memory.kmem.tcp.limit_in_bytes memory.move_charge_at_immigrate memory.swappiness
了解一下几个比较重要的概念
memory.usage_in_bytes #显示当前已用的内存
memory.limit_in_bytes #设置/显示当前限制的内存额度
memory.failcnt #显示内存使用量达到限制值的次数
memory.max_usage_in_bytes #历史内存最大使用量
memory.swappiness #设置和显示当前的swappiness
memory.oom_control #设置/显示oom controls相关的配置
加入cgroup限制
当物理内存达到上限后,系统的默认行为是kill掉cgroup中继续申请内存的进程. 通过memory.oom_control来控制.
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 0 // 0表明该进程达到其limit时会被kill, 1表明会暂停该进程
under_oom 0 // 0表明未进入oom状态, 1表明该进程被暂停
例子 oom_kill_disable = 0
root@nicktming:~# cat memory.c
#include
#include
#include
#include
#define MB (1024 * 1024)
int main(int argc, char *argv[])
{
char *p;
int i = 0;
while(1) {
p = (char *)malloc(MB);
memset(p, 0, MB);
printf("%dM memory allocated\n", ++i);
sleep(1);
}
return 0;
}
root@nicktming:/sys/fs/cgroup/memory# mkdir test-limit-memory && cd test-limit-memory
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo $$ > tasks"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 5M > memory.limit_in_bytes"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cd /root
// 可以看到在加入5M的限制后 运行程序在申请5M内存时候被killed.
root@nicktming:~# gcc memory.c -o memory
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
Killed
例子 oom_kill_disable = 1
------------------------------------打开终端0-------------------------------
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 0 > memory.swappiness"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 1 >> memory.oom_control"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 1
under_oom 0
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cd /root
// 运行到申请5M的时候会暂停该进程
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
------------------------------------打开终端1-------------------------------
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 1
under_oom 1
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 15M > memory.limit_in_bytes"
------------------------------------打开终端0-------------------------------
// 该进程继续运行
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
5M memory allocated
6M memory allocated
7M memory allocated
8M memory allocated
9M memory allocated
10M memory allocated
11M memory allocated
12M memory allocated
13M memory allocated
14M memory allocated
------------------------------------打开终端1-------------------------------
// 重新把oom_kill_disable打开
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 0 >> memory.oom_control"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 0
under_oom 0
// 可以看到该进程超过内存限制的次数
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.failcnt
85194
------------------------------------打开终端0-------------------------------
// 由于oom_kill_disable被设置为0, 所以该进程被kill.
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
5M memory allocated
6M memory allocated
7M memory allocated
8M memory allocated
9M memory allocated
10M memory allocated
11M memory allocated
12M memory allocated
13M memory allocated
14M memory allocated
Killed
参考
全部内容
mydocker.png