12. cgroup¶
cgroup (control group [1] 提供一种限制应用程序占用资源的机制。
12.1. 使用cgroup限制进程使用cpu¶
这里使用 cgroup_test.sh
做测试。
在没有做任何事情之前, 程序的运行情况如下。第一列是PID, 第二列是CPU序号(从1开始)。 可以看到脚本的主进程64793在24号CPU上运行,脚本中的sleep函数会派生一个进程,在62号CPU上运行。 观察可以发现会在CPU之间进行迁移。 sleep每执行一次,就会生成一个进程,可以很频繁的看到进程在 不同的CPU之前进行迁移
64793 24 user1 20 0 110M 1404 1184 S 0.0 0.0 0:00.30 │ │ └─ bash GoodCommand/source/script/cgroup_test.sh
69648 62 user1 20 0 105M 352 280 S 0.0 0.0 0:00.00 │ │ └─ sleep 1
执行操作步骤,注意这里的CPU需要是0开始
cd /sys/fs/cgroup/cpuset
mkdir Charlie && cd Charlie
echo 2-3 > cpuset.cpus
echo 1 > cpuset.mems
echo $$ > tasks #把当前shell的进程加入到Charlie当中
cat tasks
bash /home/user1/GoodCommand/source/script/cgroup_test.sh
观察到程序会被固定在cpu3-4上, 也就是前面固定的2-3
72077 4 root 20 0 114M 4120 1804 S 0.0 0.0 0:00.31 │ └─ bash
73899 3 root 20 0 110M 1380 1184 S 0.0 0.0 0:00.03 │ └─ bash /home/user1/GoodCommand/source/script/cgroup_test.sh
74364 3 root 20 0 105M 356 280 S 0.0 0.0 0:00.00 │ └─ sleep 1
12.2. 使用cgroup限制程序使用内存大小¶
这里使用测试程序 :Mem-limits.c
/*
* 源程序来自 https://sysadmincasts.com/episodes/14-introduction-to-linux-control-groups-cgroups
* 并进行了修改添加了死循环不退出
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
int i;
char *p;
// intro message
printf("Starting ...\n");
// loop 50 times, try and consume 50 MB of memory
for (i = 0; i < 50; ++i) {
// failure to allocate memory?
if ((p = malloc(1<<20)) == NULL) {
printf("Malloc failed at %d MB\n", i);
return 0;
}
// take memory and tell user where we are at
memset(p, 0, (1<<20));
printf("Allocated %d to %d MB\n", i, i+1);
}
// exit message and return
printf("Done!\n");
while (1) {
sleep(1);
}
return 0;
}
未作限制之前, 占用了50MB的内存
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9455 user1 20 0 55616 51824 392 S 0.0 0.0 0:00.04 mem-limit.out
创建cgroup test2,并且限制资源的使用为5MB
mkdir /sys/fs/cgroup/memory/test2
lscgroup | grep test2
echo 5242880 > /sys/fs/cgroup/memory/test2/memory.limit_in_bytes
echo 5242880 > /sys/fs/cgroup/memory/test2/memory.memsw.limit_in_bytes
程序因为受到内存限制, 申请不到内存而被kill掉
[root@intel6248 src]# cgexec -g memory:/test2 ./mem-limit.out
Starting ...
Allocated 0 to 1 MB
Allocated 1 to 2 MB
Allocated 2 to 3 MB
Allocated 3 to 4 MB
Killed
警告
memory.memsw.limit_in_bytes 是设置swap空间, 如果不设置, 程序在达到内存限制之后就会开始使用swap
12.3. 使用cgroup限制程序io速率¶
这里使用的例子来自 sysadmincasts [2]
准备测试文件,在当前目录下会生成一个1M * 3000 = 3G大小的文件
dd if=/dev/zero of=file-abc bs=1M count=3000
不做限制,测试速度
echo 3 > /proc/sys/vm/drop_caches #测试之前清除内存中的缓存
dd if=file-abc of=/dev/null
读完3G的文件速度是105MB/s
[root@intel6248 user1]# dd if=file-abc of=/dev/null
6144000+0 records in
6144000+0 records out
3145728000 bytes (3.1 GB) copied, 29.891 s, 105 MB/s
print 5*1024*1024
创建cgroup并且限制速度未5MiB/s = 5* 1024 * 1024 = 5242880 B/s
mkdir /sys/fs/cgroup/blkio/test1
lscgroup | grep test1 # 查询创建cgroup是否成功
lsblk # 查询当前硬盘的主设备号和次设备号得到是 8:0
echo "8:0 5242880" > /sys/fs/cgroup/blkio/test1/blkio.throttle.read_bps_device
读完3G的文件速度是5MB/s左右, 花了大概10分钟
[root@intel6248 user1]# cgexec -g blkio:/test1 dd if=file-abc of=/dev/null
6144000+0 records in
6144000+0 records out
3145728000 bytes (3.1 GB) copied, 600.566 s, 5.2 MB/s
iostop确认过程中读速度确实是5M左右
Total DISK READ : 5.20 M/s | Total DISK WRITE : 79.79 K/s
Actual DISK READ: 5.20 M/s | Actual DISK WRITE: 81.52 K/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
4961 be/4 root 5.20 M/s 0.00 B/s 0.00 % 99.99 % dd if=file-abc of=/dev/null
12.4. docker中的cgroup¶
docker也使用cgroup限制容器。
创建容器的时候传入cpu和memory的参数,例如限制只能使用4和5号cpu(这里是从0开始),同时限制只能使用10M内存。
docker run -itd --name docker_cgroup_restrict --rm --cpuset-cpus 4,5 -m 10m ubuntu
查询容器对应的cgroup信息, 可以看到 cpuset.cpus: 4-5 和 memory.limit_in_bytes: 10485760
lscgroup | grep docker | grep 5a1e18586f7e
[user1@intel6248 ~]$ cgget -r cpuset.cpus -r memory.limit_in_bytes /docker/5a1e18586f7e995c3c02d644eda75e7682118bf16339e0405ba4451fc02d8691
/docker/5a1e18586f7e995c3c02d644eda75e7682118bf16339e0405ba4451fc02d8691:
cpuset.cpus: 4-5
memory.limit_in_bytes: 10485760
或者显示全部变量的信息。
cgget -g cpuset:/docker/5a1e18586f7e995c3c02d644eda75e7682118bf16339e0405ba4451fc02d8691
cgget -g memory:/docker/5a1e18586f7e995c3c02d644eda75e7682118bf16339e0405ba4451fc02d8691
如果在容器中运行一个进程,这个进程会在指定核上运行。
22702 23 root 20 0 105M 9188 2772 S 0.0 0.0 0:02.17 │ ├─ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/5a1e18586f7e995c3c02d644eda75e7682118
25094 5 root 20 0 18496 1428 1200 S 0.0 0.0 0:00.07 │ │ ├─ /bin/bash
25967 5 root 20 0 18364 1604 1320 S 0.0 0.0 0:01.48 │ │ │ └+ bash nothing.sh
申请内存不能申请到超过10M的内存。
root@5a1e18586f7e:~/user1# ./mem-limit.out
Starting ...
Allocated 0 to 1 MB
Allocated 1 to 2 MB
Allocated 2 to 3 MB
Allocated 3 to 4 MB
Allocated 4 to 5 MB
Allocated 5 to 6 MB
Allocated 6 to 7 MB
Allocated 7 to 8 MB
Allocated 8 to 9 MB
Allocated 9 to 10 MB
Allocated 10 to 11 MB
Allocated 11 to 12 MB
Allocated 12 to 13 MB
Killed