cgroup 实验记录

cgroup 目录操作技巧

嵌套结构需要后序递归删除

[xiaochu.yh ~/tools/cgroup] $rmdir /sys/fs/cgroup/cpu/oceanbase/deadloop2
rmdir: failed to remove ‘/sys/fs/cgroup/cpu/oceanbase/deadloop2’: Device or resource busy
[xiaochu.yh ~/tools/cgroup] $

# 先删 child,才能删 parent
[xiaochu.yh ~/tools/cgroup] $rmdir /sys/fs/cgroup/cpu/oceanbase/deadloop2/child1
[xiaochu.yh ~/tools/cgroup] $rmdir /sys/fs/cgroup/cpu/oceanbase/deadloop2/child2
[xiaochu.yh ~/tools/cgroup] $rmdir /sys/fs/cgroup/cpu/oceanbase/deadloop2

继承属性:

# 初始化 cgroup 时检查 oceanbase/cpuset.cpus 是否设置,如果未设置,则执行
cat /sys/fs/cgroup/cpu/cpuset.cpus > /sys/fs/cgroup/cpu/oceanbase/cpuset.cpus
cat /sys/fs/cgroup/cpu/cpuset.mems > /sys/fs/cgroup/cpu/oceanbase/cpuset.mems

# 开启 oceanbase 这个组的继承属性
# 后面创建的任何子 group 都无需再设置 cpuset.mems 和 cpuset.cpus,简化操作
echo 1 > /sys/fs/cgroup/cpu/oceanbase/cgroup.clone_children

多个子系统,可以指向同一个目录。取决于 mount 命令。

A 机器上的 效果:

[xiaochu.yh ~/tools/cgroup] $ll /sys/fs/cgroup/
total 0
drwxr-xr-x 3 root root  0 May  7 18:59 blkio
lrwxrwxrwx 1 root root 33 May  7 18:59 cpu -> /sys/fs/cgroup/cpuset,cpu,cpuacct
lrwxrwxrwx 1 root root 33 May  7 18:59 cpuacct -> /sys/fs/cgroup/cpuset,cpu,cpuacct
lrwxrwxrwx 1 root root 33 May  7 18:59 cpuset -> /sys/fs/cgroup/cpuset,cpu,cpuacct
drwxr-xr-x 4 root root  0 Aug 20 18:04 cpuset,cpu,cpuacct
drwxr-xr-x 3 root root  0 May  7 18:59 devices
drwxr-xr-x 2 root root  0 May  7 18:59 freezer
drwxr-xr-x 2 root root  0 May  7 18:59 hugetlb
drwxr-xr-x 2 root root  0 Apr 19 15:44 intel_rdt
drwxr-xr-x 3 root root  0 May  7 18:59 memory
drwxr-xr-x 2 root root  0 May  7 18:59 net_cls
drwxr-xr-x 2 root root  0 May  7 18:59 perf_event
drwxr-xr-x 2 root root  0 May  7 18:59 pids
drwxr-xr-x 3 root root  0 May  7 18:59 systemd

$mount | grep cpu
cgroup on /sys/fs/cgroup/cpuset,cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu,cpuset)

B 机器上的效果:

$ll /sys/fs/cgroup/
total 0
drwxr-xr-x 5 root root  0 Jun 24  2019 blkio
lrwxrwxrwx 1 root root 11 Jun 24  2019 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jun 24  2019 cpuacct -> cpu,cpuacct
drwxr-xr-x 8 root root  0 Jun 24  2019 cpu,cpuacct
drwxr-xr-x 3 root root  0 Jun 24  2019 cpuset
drwxr-xr-x 4 root root  0 Jun 24  2019 devices
drwxr-xr-x 2 root root  0 Jun 24  2019 freezer
drwxr-xr-x 2 root root  0 Jun 24  2019 hugetlb
drwxr-xr-x 7 root root  0 Jun 24  2019 memory
drwxr-xr-x 2 root root  0 Jun 24  2019 net_cls
drwxr-xr-x 2 root root  0 Jun 24  2019 perf_event
drwxr-xr-x 4 root root  0 Jun 24  2019 systemd

$ll /sys/fs/cgroup/cpuset
total 0
drwxr-xr-x 3 root root 0 Aug 27  2019 agent
-rw-r--r-- 1 root root 0 Jun 24  2019 cgroup.clone_children
--w--w--w- 1 root root 0 Jun 24  2019 cgroup.event_control
-rw-r--r-- 1 root root 0 Jun 24  2019 cgroup.procs
-r--r--r-- 1 root root 0 Jun 24  2019 cgroup.sane_behavior
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.cpus
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.memory_migrate
-r--r--r-- 1 root root 0 Jun 24  2019 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.memory_pressure_enabled
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.mems
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 Jun 24  2019 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 Jun 24  2019 notify_on_release
-rw-r--r-- 1 root root 0 Jun 24  2019 release_agent
-rw-r--r-- 1 root root 0 Jun 24  2019 tasks

$mount | grep cpu
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)

实验效果

# 分别启动 3 个 进程
./a.out deadloop2 100
./a.out deadloop2/child1 100
./a.out deadloop2/child2  100

背后对应了3组命令序列:

mkdir /sys/fs/cgroup/cpu/oceanbase/deadloop2/;
echo 5 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/cpuset.mems
echo 50000 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/cpu.cfs_quota_us

mkdir /sys/fs/cgroup/cpu/oceanbase/deadloop2/child1;
echo 5 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child1/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child1/cpuset.mems
echo 50000 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child1/cpu.cfs_quota_us

mkdir /sys/fs/cgroup/cpu/oceanbase/deadloop2/child2;
echo 5 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child2/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child2/cpuset.mems
echo 50000 > /sys/fs/cgroup/cpu/oceanbase/deadloop2/child2/cpu.cfs_quota_us

这时,三个进程均占用 1/3 CPU,总大小为 50%。其中 50% 是由 cpu.cfs_quota_us 定义。

改进实验

如果我希望建立优先级,deadloop2 执行的时候, child1、child2 都不执行,当 deadloop2 退出时,child1、child2 分配 cpu 资源。

在 cgroup 下能否实现?用 cpu.shares 就行。

费解

 87209 xiaochu.  20   0  9376  128    0 R 56.8  0.0   0:11.03 ./a.out deadloop/child1 4000
 86104 xiaochu.  20   0  9376  128    0 R 28.6  0.0   1:04.57 ./a.out deadloop/child2 2000
 87253 xiaochu.  20   0  9376  124    0 R 14.6  0.0   0:02.32 ./a.out deadloop 20000

顶层的 share 会优先分给 child,然后再满足顶层需求。

搞明白了

 10932 xiaochu.  20   0  9376  120    0 R 66.8  0.0   3:14.17 ./a.out deadloop2 200
 10696 xiaochu.  20   0  9376  128    0 R 20.9  0.0   1:32.62 ./a.out deadloop/child1 1900
  9732 xiaochu.  20   0  9376  124    0 R 11.3  0.0   2:28.04 ./a.out deadloop 100
 10609 xiaochu.  20   0  9376  124    0 R  1.0  0.0   0:05.83 ./a.out deadloop/child2 100

逻辑是这样的:

  1. 同层,按照同层的 shares 来分 cpu。比如:
    deadloop2 占 66%; deadloop 33%。
  2. 比较费解的部分:deadloop 33% 怎么分给 child1, child2, deadloop 自己?
  • 33% 3 个人分
  • deadloop 上没有定义任何值(100 是用来和 200 比的,比完就作废)
  • 算法是基准为 1024 即:parent 的 shares 总是 1024
  • deadloop 占 1024, child1 占 1900, child2 占 100, total = 1024+1900+100 = 3024。
  • 所以 deadloop = 33% * 1024 / 3024 = 11.2%child1 = 33% * 1900 / 3024 = 20.7%; child2 = 1.1%
    和 上面的截图相符合。

再来个例子:

10932 xiaochu.  20   0  9376  120    0 R 66.8  0.0  72:35.65 ./a.out deadloop2 200
  9732 xiaochu.  20   0  9376  124    0 R 25.6  0.0  14:19.96 ./a.out deadloop 100
 42711 xiaochu.  20   0  9376  120    0 R  5.0  0.0   0:02.20 ./a.out deadloop/child1 200
 10609 xiaochu.  20   0  9376  124    0 R  2.7  0.0   1:15.36 ./a.out deadloop/child2 100

第一层,200:100,所以 cpu 是 66.8% : 32.3%
第二层,deadloop 是 1024;1024+200+100,然后分,得到 cpu 是 25.6%, 5%, 2.5%

尚存的疑惑

但是,这仅仅适用于单线程程序。如果程序变成多线程,又是一番景象! ./thread有20 个工作线程,shares 都设置为 1024,cpu 效果如下:
在这里插入图片描述
这个暂时没有找到合理的解释。

再举个栗子:把 ./thread 代码改一下,改成内部启动 4 个工作线程的版本,shares 依然都是 1024:
在这里插入图片描述
child 和 parent 的 cpu 比例是 1:4。难以解释把?

Best Practice

建议 cgroup 在 deadloop 那一层不要跑任何程序,上面配置的 shares 只用于和其它兄弟层级做 cpu 配比。

附录

程序如下,为自己在 cgroup 中创建一个目录,并开始死循环压 CPU。

// [xiaochu.yh ~/tools/cgroup] $cat main.c
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

#define STACK_SIZE (1024 * 1024)

int pipefd[2];
static char container_stack[STACK_SIZE];

int container_main(void* arg)
{
  char ch;
  int i = 0;
  close(pipefd[1]);
  read(pipefd[0], &ch, 1);
  printf("start\n");
  for(;;)i++;
  return 1;
}

int main(int argc, char** argv)
{
  if (argc != 3) {
    printf("Wrong Arg. specify hierachy\n");
    return 1;
  }

  char *h = argv[1];
  char *quota = argv[2];
  char cmd[128];
  printf("Parent - start a container!\n");
  /* 设置CPU利用率为50% */
  sprintf(cmd, "/sys/fs/cgroup/cpu/oceanbase/%s/", h);
  mkdir(cmd, 0755);

  sprintf(cmd, "echo 5 > /sys/fs/cgroup/cpu/oceanbase/%s/cpuset.cpus", h);
  printf("run cmd:%s!\n", cmd);
  system(cmd);

  sprintf(cmd, "echo 0 > /sys/fs/cgroup/cpu/oceanbase/%s/cpuset.mems", h);
  printf("run cmd:%s!\n", cmd);
  system(cmd);

 // sprintf(cmd, "echo %s > /sys/fs/cgroup/cpu/oceanbase/%s/cpu.cfs_quota_us", quota, h);
  sprintf(cmd, "echo %s > /sys/fs/cgroup/cpu/oceanbase/%s/cpu.shares", quota, h);
  printf("run cmd:%s!\n", cmd);
  system(cmd);
  pipe(pipefd);
  /* 调用clone函数,其中传出一个函数,还有一个栈空间的(为什么传尾指针,因为栈是反着的) */
  int container_pid = clone(container_main, container_stack+STACK_SIZE, SIGCHLD ,NULL);
  sprintf(cmd, "echo %d >> /sys/fs/cgroup/cpu/oceanbase/%s/tasks",container_pid, h);
  printf("PID:%d!\n", container_pid);
  system(cmd);
  close(pipefd[1]);
  waitpid(container_pid, NULL, 0);
  printf("Parent - container stopped!\n");
  return 0;
}

参考

https://www.infoq.cn/article/docker-kernel-knowledge-cgroups-resource-isolation

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值