zoukankan      html  css  js  c++  java
  • Linux系统中cgroup功能介绍

    1  Cgroups简介
    1.1 What are cgroups ?
    Cgroups(控制组)是Linux内核的一个功能,用来限制、统计和分离一个进程组的资源(CPU、内存、磁盘输入输出等)。换句话说就是,如果一个进程加入了某一个控制组,该控制组对Linux的系统资源都有严格的限制,进程在使用这些资源时,不能超过其最大的限制数,例如:memory资源,如果加入控制组的进程使用的memory大于其限制,可能会出现OOM错误(关于OOM错误可参看Linux内核OOM机制分析)。cgroup本身提供将进程进行分组化管理的功能和接口的基础结构
    控制组提供一种机制,将一组任务和它们的子任务聚合或划分到有特定功能的层级结构(hierarchical)中。在Cgroups中涉及下面的几个概念:
    (1)任务(task):在 cgroups 中,任务就是系统的一个进程。
    (2)控制族群(control group):控制族群就是一组按照某种资源限制划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到多个控制族群。假设这里有个进程A,我们要限制其使用的系统内存总量的10%,我们就可以创建一个memory占用10%的cgroups。然后,将进程A添加到cgroups,那么进程A最多占用内存总量的10%,当然,一个cgroups一般情况下不止一个进程。
    (3)层级(hierarchy):控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。子控制组自动继承父节点的特定属性,当然子控制组还可以有自己特定的属性。下面是Linux内核关于Cgroups的一种图示:可以看出他的层级表示:
    .CPU :          "Top cpuset"
                           /       
                   CPUSet1         CPUSet2
                      |               |
                   (Professors)    (Students)
     
                   In addition (system tasks) are attached to topcpuset (so
                   that they can run anywhere) with a limit of 20%
     
           Memory : Professors (50%), Students (30%), system (20%)
     
           Disk : Professors (50%), Students (30%), system (20%)
     
           Network : WWW browsing (20%), Network File System (60%), others (20%)
                                   / 
                   Professors (15%)  students (5%)
     
    Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes
    into the NFS network class.(参考Linux内核的cgroups说明
    (4)Subsystem:子系统是任务组中的一个模块,例如前面的memory就是一个子系统,该子系统是一个内存控制器。在cgroups的框架下,为cgroups提供多种资源限制。(each subsystem has system-specific state attached to each cgroup in the hierarchy.  Each hierarchy has an instance of the cgroup virtual filesystem associated with it)。
    1.2  Cgroups子系统介绍
    (1)blkio --为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等)。
    (2)cpu -- 使用调度程序提供对<span "="">CPU的cgroup任务访问。
    (3)cpuacct --自动生成cgroup中任务所使用的CPU资源报告。
    (4)cpuset --为cgroup中的任务分配独立CPU(在多核系统)和内存节点。
    (5)devices --可允许或者拒绝中的任务对设备的访问。
    (6)freezer --挂起或者恢复cgroup中的任务。
    (7)memory --设定 cgroup 中任务使用的内存限制,并自动生成任务使用的内存资源报告。
    (8)net_cls--使用等级识别符(classid)标记网络数据包,可允许 Linux  流量控制程序(tc)识别从具体 cgroup 中生成的数据包。
    (9)net_prio--允许管理员动态的通过各种应用程序设置网络传输的优先级,类似于socket 选项的SO_PRIORITY,但它有它自身的优势。
    (10)HugeTLB--HugeTLB页的资源控制功能
             上面的几种子系统特性可以参考Linux的文档cgoups子特性文档
    1.3  Cgroups在Linux中的使用和安装
    Cgroups是从Linux内核版本2.6.24开始添加进去的,Cgroups最初是由Google的工程师在2006年开发的,起初的名字叫“process containers”,在2007年改名为“Control Groups”。首先,确定使用的Linux发行版本是否支持该特性,我这里使用的Linux发行版本是ubuntu,可以使用下面的方式查看Ubuntu的版本。
    root@ubuntu:~# lsb_release -a
    No LSB modules are available.
    Distributor ID:           Ubuntu
    Description:               Ubuntu Trusty Tahr (development branch)
    Release:   14.04
    Codename:                trusty
                       使用下面的命令可以查看Ubuntu使用的Linux内核版本。
    root@ubuntu:~# uname -r
    3.13.0-12-generic
                       在我的Ubuntu系统中执行lssubsys –all查看系统中默认挂载的子系统。检查Linux内核是否支持,可以使用下面的命令:
    grep CGROUP /boot/config-`uname -r`
    cgroup-bin_0.38-1ubuntu2_i386版本中的etc目录下已经没有了cgconfig.conf文件,但是我们可以自己创建该配置文件,这样但cggroup启动时,就会读取该配置文件。这个配置文件包括mount , group and default 三个段,这三个段的顺序是任意的,并且都是可选参数,该文件中用#表示的注释。
    mount section has this form:
     
                  mount {
                         <controller> = <path>;
                         ...
                  }
    Controller:
                       表示内核支持的子系统的名字。通过/proc/cgroups文件查看系统中支持子系统。
    Path:
    子系统的挂载点。
                       如果没有mount段,则controllers不会被挂载。
    group section has this form:
     
                  group <name> {
                         [permissions]
                         <controller> {
                                <param name> = <param value>;
                                ...
                         }
                         ...
                  }
    Name:
    control group的名字,只能包括目录名字允许的字符。
    permissions:
    可选项,指定cgroup对应的挂载点文件系统的权限
    Controller:
                       内核中支持的子系统的名字。
    param name,param value:参数的名字和参数的值。
                       如果没有group,则就没有group被创建。
    Default段如下面的形式:
    default {
                         perm {
                                task {
                                       uid = <task user>;
                                       gid = <task group>;
                                       fperm = <file permissions>
                                }
                                admin {
                                       uid = <admin name>;
                                       gid = <admin group>;
                                       dperm = <directory permissions>
                                       fperm = <file permissions>
                                }
                         }
                  }
    下面举两个例子:
    mount {#定义需要创建的cgroup子系统及其挂载点,这里创建cpu与cpuacct(统计)两个cgroup子系统
                         cpu = /mnt/cgroups/cpu;
                         cpuacct = /mnt/cgroups/cpu;
                  }
    和下面的shell脚本是等价的:
       mkdir /mnt/cgroups/cpu
       mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/c
    group daemons/www {
                         perm {#定义组的权限
                                task {
                                       uid = root;
                                       gid = webmaster;
                                       fperm = 770;
                                }
                                admin {
                                       uid = root;
                                       gid = root;
                                       dperm = 775;
                                       fperm = 744;
                                }
                         }
                         cpu {
                                cpu.shares = "1000";
                         }
                  }
     
                  group daemons/ftp {
                         perm {
                                task {
                                       uid = root;
                                       gid = ftpmaster;
                                       fperm = 774;
                                }
                                admin {
                                       uid = root;
                                       gid = root;
                                       dperm = 755;
                                       fperm = 700;
                                }
                         }
                         cpu {
                                cpu.shares = "500";
                         }
                  }
    相当于使用下面的脚本:
    mkdir /mnt/cgroups/cpu
                  mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/cpu
     
                  mkdir /mnt/cgroups/cpu/daemons
     
                  mkdir /mnt/cgroups/cpu/daemons/www
                  chown root:root /mnt/cgroups/cpu/daemons/www/*
                  chown root:webmaster /mnt/cgroups/cpu/daemons/www/tasks
                  echo 1000 > /mnt/cgroups/cpu/daemons/www/cpu.shares
                       上面的具体内容可以参考,cfconfig.conf文件说明
    1.4 用户空间挂载Cgroup
                       上面我们分析了一下,cgroup的配置文件,这里我们具体分析一下使用命令如何进行配置。我们知道cgroup的实现有一个文件系统的支持,用户空间的配置可以使用cgroup文件系统。首先,我们可以创建一个层级:在创建层级之前我们需要创建挂载的目录,这里使用的目录是/home/ubuntu /test_cgroup
    root@ubuntu:~# mount -t cgroup -o cpu cpu_group /home/ubuntu/test_cgroup/
    这个命令就是创建了一个test_cgroup的层级,这个层级有一个子系统cpu,并把层级挂载到了/home/ubuntu /test_cgroup目录下。进入该目录可以看到一些和CPU相关的参数。
    root@ubuntu:~# cd test_cgroup/
    root@ubuntu:~/test_cgroup# ls
    cgroup.clone_children  cpu.cfs_period_us  cpu.shares         tasks
    cgroup.event_control   cpu.cfs_quota_us   cpu.stat       cgroup.procs           cpu.rt_period_us   notify_on_release
    cgroup.sane_behavior   cpu.rt_runtime_us  release_agent
    然后创建一个cgroup,名字为foo
    root@ubuntu:~/test_cgroup# mkdir foo
    root@ubuntu:~/test_cgroup# cd foo/
    root@ubuntu:~/test_cgroup/foo# ls
    cgroup.clone_children  cpu.cfs_period_us  cpu.rt_runtime_us  notify_on_release
    cgroup.event_control   cpu.cfs_quota_us   cpu.shares         tasks
    cgroup.procs           cpu.rt_period_us   cpu.stat
                 这样就在cpu_group层级上创建了一个foo的cgroup,在Foo目录下有一些文件,这些都是CPU相关的属性。其中cat ~/test_cgroup/task可以看到系统中的所有进程ID。这是因为每创建一个层级,系统会把系统中所以的进程ID添加到task中,而在foo/task文件却是空,这个文件用户可以添加。
    在/proc/下面有一个cgroups的文件,记录了所有cgroups子系统的状态信息。
    root@ubuntu:~/test_cgroup/foo# cat /proc/cgroups
    #subsys_name    hierarchy num_cgroups            enabled
    cpuset                   3                 1                 1
    cpu      4                 3                 1
    cpuacct                 5                 1                 1
    memory                6                 2                 1
    devices                  7                 1                 1
    freezer                  8                 1                 1
    blkio    9                 1                 1
    perf_event           10              1                 1
    hugetlb                  11              1                 1
                 从左到右的条目分别是子系统name,hierarchy ID,子系统的cgroup控制组数目,子系统是否可用(1可用,0不可用)
    /proc/mounts文件显示了系统中挂载的文件系统信息,前面几个目录表示文件系统name,挂载点绝对路径,文件系统类型
    root@ubuntu:~/test_cgroup/foo# cat /proc/mounts
    rootfs / rootfs rw 0 0
    sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
    udev /dev devtmpfs rw,relatime,size=503368k,nr_inodes=125842,mode=755 0 0
    devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
    tmpfs /run tmpfs rw,nosuid,noexec,relatime,size=102556k,mode=755 0 0
    /dev/disk/by-uuid/612dacd9-3cf7-471b-92a4-f5c7c6e4e88a / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
    none /sys/fs/cgroup tmpfs rw,relatime,size=4k,mode=755 0 0
    none /sys/fs/fuse/connections fusectl rw,relatime 0 0
    none /sys/kernel/debug debugfs rw,relatime 0 0
    none /sys/kernel/security securityfs rw,relatime 0 0
    none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
    none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0
    none /run/user tmpfs rw,nosuid,nodev,noexec,relatime,size=102400k,mode=755 0 0
    none /sys/fs/pstore pstore rw,relatime 0 0
    systemd /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,name=systemd 0 0
    vmware-vmblock /run/vmblock-fuse fuse.vmware-vmblock rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other 0 0
    gvfsd-fuse /run/user/1000/gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0
    cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,cpuset 0 0
    cgroup /sys/fs/cgroup/cpu cgroup rw,relatime,cpu 0 0
    cgroup /sys/fs/cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
    cgroup /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
    cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
    cgroup /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0
    cgroup /sys/fs/cgroup/blkio cgroup rw,relatime,blkio 0 0
    cgroup /sys/fs/cgroup/perf_event cgroup rw,relatime,perf_event 0 0
    cgroup /sys/fs/cgroup/hugetlb cgroup rw,relatime,hugetlb 0 0
    gvfsd-fuse /root/.gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=0,group_id=0 0 0
    test_group /home/zfz/cgroup cgroup rw,relatime,cpu 0 0
    cpu_group /home/zfz/test_cgroup cgroup rw,relatime,cpu 0 0
    1.5  Cgroup使用实例
    用lssubsys -al来列出系统支持多少种子系统,和使用ls /sys/fs/cgroup/ (ubuntu)来显示已经挂载的子系统。
    如果提示下面的错误信息,则表示系统中还没有安装cgroup.
    lssubsys -all
    The program 'lssubsys' is currently not installed. You can install it by typing:
                       需要使用下面的方法进行安装:
    root@ubuntu:~# apt-get install cgroup-bin
    Reading package lists... Done
                       再次使用lssubsys列出系统中支持的子系统,根据不同的内核版本,支持的子系统也不相同。
    root@ubuntu:~# lssubsys --all
    cpuset
    cpu
    cpuacct
    memory
    devices
    freezer
    blkio
    perf_event
    hugetlb
                       还有一种情况需要进行确认,确认相应的内核部分是否已经编译。
    grep CGROUP /boot/config-`uname -r`
    CONFIG_CGROUPS=y
    # CONFIG_CGROUP_DEBUG is not set
    CONFIG_CGROUP_FREEZER=y
    CONFIG_CGROUP_DEVICE=y
    CONFIG_CGROUP_CPUACCT=y
    CONFIG_CGROUP_HUGETLB=y
    CONFIG_CGROUP_PERF=y
    CONFIG_CGROUP_SCHED=y
    CONFIG_BLK_CGROUP=y
    # CONFIG_DEBUG_BLK_CGROUP is not set
    CONFIG_NET_CLS_CGROUP=m
    CONFIG_NETPRIO_CGROUP=m
                       我们可以创建一个cgroup的cpu子系统,创建完成之后就在该目录下有下面的属性文件可以进行设置。
       root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# ls
    cgroup.clone_children  cpu.cfs_period_us  cpu.rt_runtime_us  notify_on_release
    cgroup.event_control   cpu.cfs_quota_us   cpu.shares         tasks
    cgroup.procs           cpu.rt_period_us   cpu.stat
                       使用cat命令查看其中的默认值。
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_quota_us
    -1
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_period_us
    100000
    默认挂载在/sys/fs/cgroup/memory,可以通过cfconfig.conf文件查看默认的挂载点。这里有两个小的例子主要是为了测试cgroup对进程使用CPU和memeory的控制,这里使用两个Python脚本来模拟其中的效果。
    例子1:设置该进程对CPU的占用率不能超过50%。
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# echo 50000 > cpu.cfs_quota_us
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_quota_us
    50000
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat tasks
    root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# echo 9477 > tasks
    使用的Python程序如下:
    root@ubuntu:~# cat python_test_cpu.py
    #!/usr/bin/env python
    import os
    pid_num = os.getpid()
    print pid_num
    var = 1
    count = 1
    while var == 1:
        count = count + 1
    count = 0
     
    在没有把python的进程号添加到tasks中,该进程的CPU占用率接近95%。而把该进程ID添加到tasks中经过持续的观察,该进程的CPU使用率不超出50%,和在cgroup中设置的一致。
    
    
    例子2:限制内存的使用率
                       Python代码如下:
    root@ubuntu:~# cat python_test_memory.py
    #!/usr/bin/env python
    import os
    import time
    pid_num = os.getpid()
    print pid_num
    var = 1
    a = "abcdefgh"
    b = "abcdefgh"
    c = ""
    time.sleep(10)
    #while var == 1:
    for i in range(1,30000000):
        c = "####".join([a,b]) + c
                       在没有使用cgroups机制的情况下,通过top命令查看该进程占用的memory情况如下:
    
    
    持续观察一段时间基本维持在40%左右。在使用cgoup机制,限制在10M的情况下,其内存的占有率发生了变化。
    root@ubuntu:/sys/fs/cgroup/memory/memory_test# echo 10M > memory.limit_in_bytes
    root@ubuntu:/sys/fs/cgroup/memory/memory_test# cat memory.limit_in_bytes
    10485760
    
    
                       过一小段时间会出现进程退出的情况,如下:进程被杀掉了。
    root@ubuntu:~# ./python_test_memory.py
    10608
    [8]+  Killed                  ./python_test_memory.py
    Killed
     在这里也可以配置内核的OOM机制,默认值是开着呢。
    root@ubuntu:/sys/fs/cgroup/memory/memory_test# cat memory.oom_control
    oom_kill_disable 0
    under_oom 0
                 在上面我们设置的是memory.limit_in_bytes 值,但在目录下还有一个memory.soft_limit_in_bytes 属性,,该值和 memory.limit_in_bytes 的差异是,memory.soft_limit_in_bytes这个限制并不会阻止进程使用超过限额的内存,只是在系统内存不足时,会优先回收超过限额的进程占用的内存,使之向限定值靠拢
    通过上面的分析可以看出来,简单的说Cgroup就是限制了各个不同进程之间使用各种资源的能力。上面两个例子是最常用的CPU和内存,每一个内核子系统都有很多的配置选项信息,其中配置选项的含义可以参考Linux内核文档,Linux的Cgroup子系统解释。Cgroup做到对资源的限制访问,这对于Linux系统上的虚拟化和云计算提供了一种资源配置方式。
    参考文献:
    http://blog.chinaunix.net/uid-20940095-id-3294134.html
    http://files.cnblogs.com/lisperl/cgroups介绍.pdf
  • 相关阅读:
    C++:怎样把一个int转成4个字节?
    安装虚拟机
    [Flux] 1. Development Environment Setup
    [CSS] Animating SVG
    [Node.js] Scraping Dynamic JavaScript Websites with Nightmare
    [React] React Fundamentals: Integrating Components with D3 and AngularJS
    [React] React Fundamentals: with-addons
    [JavaScript] Array.prototype.reduce in JavaScript by example
    [CSS] @keyframes
    [CSS] Transforms
  • 原文地址:https://www.cnblogs.com/jackhub/p/4308254.html
Copyright © 2011-2022 走看看