• 容器基础(三): 使用Cgroups进行资源限制


    Linux Cgroups 

    Linux Cgroups 是 Linux 内核中用来为进程设置资源限制的一个重要功能. Cgroups将进程进行分组, 然后对这一组进程进行统一的资源监控和限制。Cgroups当前有V1和V2版本,为了后续用于实现简单容器sdocker,这里只验证V1版本的cpu和memory子系统。

    Linux可以通过如下命令来查看当前系统支持的cgroup子系统:

     1 linux: # cat /proc/cgroups
     2 #subsys_name    hierarchy       num_cgroups     enabled
     3 cpuset          11      1       1
     4 cpu             2       78      1
     5 cpuacct         2       78      1
     6 blkio           3       78      1
     7 memory          9       79      1
     8 devices         4       78      1
     9 freezer         8       1       1
    10 net_cls         7       78      1
    11 perf_event      5       1       1
    12 net_prio        7       78      1
    13 hugetlb         6       1       1
    14 pids            10      86      1
    15 linux: #

    有的系统(debian8/suse12), cgroup.memory没有启用, 这时可能会影响到下面几个方面:

    1. 在/sys/fs/cgroup/memory下建立目录失败, 提示readonly;
    2. docker info里面也会有提示信息;
    3. 使用kubeadm安装kubernetes时会提示错误;

    解决办法, 在/etc/default/grub文件中增加如下选项(debian使用update_grub, suse使用grub2-mkconfig, 然后reboot):

    1 linux: # cat /etc/default/grub  | grep cgroup_enable
    2 GRUB_CMDLINE_LINUX="cgroup_enable=memory"
    3 linux: #

    Cgroup.CPU

    对于Cgroup.CPU,限制cpu利用率主要通过修改下面两个文件来实现:

    1 /sys/fs/cgroup/cpu/cpu.cfs_quota_us
    2 /sys/fs/cgroup/cpu/cpu.cfs_period_us

    把cpu.cfs_quota_us / cpu.cfs_period_us(默认100000)的值作为可以使用的CPU的百分比。使用方法举例如下(摘录自附录网页):

     1 Examples
     2 --------
     3 1. Limit a group to 1 CPU worth of runtime.
     4 
     5     If period is 250ms and quota is also 250ms, the group will get
     6     1 CPU worth of runtime every 250ms.
     7 
     8     # echo 250000 > cpu.cfs_quota_us /* quota = 250ms */
     9     # echo 250000 > cpu.cfs_period_us /* period = 250ms */
    10 
    11 2. Limit a group to 2 CPUs worth of runtime on a multi-CPU machine.
    12 
    13     With 500ms period and 1000ms quota, the group can get 2 CPUs worth of
    14     runtime every 500ms.
    15 
    16     # echo 1000000 > cpu.cfs_quota_us /* quota = 1000ms */
    17     # echo 500000 > cpu.cfs_period_us /* period = 500ms */
    18 
    19     The larger period here allows for increased burst capacity.
    20 
    21 3. Limit a group to 20% of 1 CPU.
    22 
    23     With 50ms period, 10ms quota will be equivalent to 20% of 1 CPU.
    24 
    25     # echo 10000 > cpu.cfs_quota_us /* quota = 10ms */
    26     # echo 50000 > cpu.cfs_period_us /* period = 50ms */
    27 
    28     By using a small period here we are ensuring a consistent latency
    29     response at the expense of burst capacity.

    针对Cgroup.CPU进行测试,对于如下的cpu密集型程序, 启动后从top中可以看到cpu占用100%:

    1 linux: # cat cpu.c
    2 int main(void) {
    3   for (; ;);
    4 
    5   return 0;
    6 }
    7 linux: #
    1 PID USER      PR  NI    VIRT    RES    SHR S   %CPU  %MEM     TIME+ COMMAND
    2 4033 root      20   0    4052    708    632 R 100.00 0.002   1:33.02 cpu

    通过给cpu.cfs_quota_us赋值20000,同时把程序pid赋值给tasks文件,让程序只能使用1/5的cpu。

    1 linux: # mkdir /sys/fs/cgroup/cpu/sdocker
    2 linux: # mkdir /sys/fs/cgroup/cpu/sdocker/4033
    3 linux: # echo 20000 > /sys/fs/cgroup/cpu/sdocker/4033/cpu.cfs_quota_us
    4 linux: # echo 4033 > /sys/fs/cgroup/cpu/sdocker/4033/tasks

     设置后立即生效,top可以看到进程cpu占用率在20%左右波动:

    1 PID USER      PR  NI    VIRT    RES    SHR S   %CPU  %MEM     TIME+ COMMAND
    2 4033 root      20   0    4052    708    632 R 20.202 0.002   1:57.80 cpu

    退出程序并清理cgroup资源:

    1 linux: # kill -9 4033  
    2 linux: # rmdir /sys/fs/cgroup/cpu/sdocker/4033/

     Cgroup.Memory

    /sys/fs/cgroup/memory下定义了Cgroup.Memory子系统的相关文件, 各文件含义如下:

     1  cgroup.event_control       #用于eventfd的接口
     2  memory.usage_in_bytes      #显示当前已用的内存字节数
     3  memory.limit_in_bytes      #设置/显示当前限制的内存额度, 当usage_in_bytes超限时, 如果memory.swappiness配置可使用swap, kernel会优先把内存数据转移到swap空间, 最后若转移swap失败, 则根据memory.oom_control判断是否触发oom
     4  memory.failcnt             #显示内存使用量达到限制值的次数, 当usage_in_bytes超限时, 会触发该值增加
     5  memory.max_usage_in_bytes  #历史内存最大使用量
     6  memory.soft_limit_in_bytes #设置/显示当前限制的内存软额度
     7  memory.stat                #显示当前cgroup的内存使用情况
     8  memory.use_hierarchy       #设置/显示是否将子cgroup的内存使用情况统计到当前cgroup里面
     9  memory.force_empty         #触发系统立即尽可能的回收当前cgroup中可以回收的内存
    10  memory.pressure_level      #设置内存压力的通知事件,配合cgroup.event_control一起使用
    11  memory.swappiness          #设置和显示当前的swappiness
    12  memory.move_charge_at_immigrate #设置当进程移动到其他cgroup中时,它所占用的内存是否也随着移动过去
    13  memory.oom_control         #设置/显示oom controls相关的配置, 默认0启用
    14  memory.numa_stat           #显示numa相关的内存

    针对Cgroup.Memory进行测试,如下的测试代码通过不断分配内存来触发内存限制功能:

     1 linux: # cat memory.cpp
     2 #include <unistd.h>
     3 
     4 #include <csignal>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <cstring>
     8 #include <vector>
     9 using std::vector;
    10 
    11 vector<int *> g_mem_pointer;
    12 
    13 void sig_handler(int sig) {
    14   printf("
    %d handle
    ", sig);
    15   for (auto p : g_mem_pointer) {
    16     free(p);
    17   }
    18 
    19   exit(-1);
    20 }
    21 
    22 int main(void) {
    23   unsigned total_mem = 0, chunk_size = 1024 * 1024;
    24 
    25   signal(SIGTERM, sig_handler);
    26   signal(SIGINT, sig_handler);
    27 
    28   int *p;
    29   while (1) {
    30     if (NULL == (p = (int *)malloc(chunk_size))) {
    31       printf("[-] malloc failed!
    ");
    32       kill(getpid(), 15);
    33     }
    34 
    35     memset(p, 0xff, chunk_size);
    36     g_mem_pointer.push_back(p);
    37     total_mem += chunk_size;
    38     printf("[+] malloc size: %u
    ", total_mem);
    39     sleep(10);
    40   }
    41 
    42   return 0;
    43 }
    44 linux: #
    memory.cpp

    设置内存限制6m到memory.limit_in_bytes,同时把进程pid设置到tasks文件, 一段时间后可以看到进程oom-kill.

    测试发现进程实际打印分配的总内存远远大于设置的内存上限时,  memory.usage_in_bytes中的数值才会慢慢趋近于memory.limit_in_bytes,即使设置memory.swappiness为0也如此;

    1 linux:~ # mkdir /sys/fs/cgroup/memory/sdocker
    2 linux:~ # mkdir /sys/fs/cgroup/memory/sdocker/5239
    3 linux:~ # echo 6m > /sys/fs/cgroup/memory/sdocker/5239/memory.limit_in_bytes
    4 linux:~ # cat /sys/fs/cgroup/memory/sdocker/5239/memory.limit_in_bytes
    5 32768
    6 linux:~ # echo 5239 > /sys/fs/cgroup/memory/sdocker/5239/tasks
    7 linux:~ # rmdir /sys/fs/cgroup/memory/sdocker/5239

    参考网址:

    1 https://segmentfault.com/u/wuyangchun
    2 https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
    3 https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt

    Excellence, is not an act, but a habit.
    作者:子厚.
    出处:http://www.cnblogs.com/aios/
    本文版权归作者和博客园共有,欢迎转载、交流、点赞、评论,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    【转载】Dom篇
    【转载】Eclipse自动编译问题
    RabbitMQ
    分布式消息中间件
    分布式限流算法
    分布式限流和熔断
    数据库中间件
    redis 集群原理
    redis 哨兵模式(读写分离)
    redis 和memcache 区别
  • 原文地址:https://www.cnblogs.com/aios/p/10032990.html
Copyright © 2020-2023  润新知