您的位置:新葡亰496net > 服务器网络 > 新葡亰496net:Cgroup和Namespace在测试中的使用,L

新葡亰496net:Cgroup和Namespace在测试中的使用,L

发布时间:2019-06-19 08:48编辑:服务器网络浏览(146)

    Linux下CGroup进行CPU、内存等资源控制,linuxcgroup

    留存

    from:   and 

    CGroup 介绍
    CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。

    CGroup 功能及组成
    CGroup 是将任意进程进行分组化管理的 Linux 内核功能。CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 CGroup 子系统或控制器。CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。
    CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用 CGroup,必须挂载 CGroup 文件系统。这时通过挂载选项指定使用哪个子系统。

    Cgroups提供了以下功能:
    1)限制进程组可以使用的资源数量(Resource limiting )。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
    2)进程组的优先级控制(Prioritization )。比如:可以使用cpu子系统为某个进程组分配特定cpu share。
    3)记录进程组使用的资源数量(Accounting )。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
    4)进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
    5)进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。

    CGroup 支持的文件种类
    表 1. CGroup 支持的文件种类

    文件名 R/W 用途

    Release_agent

    RW

    删除分组时执行的命令,这个文件只存在于根分组

    Notify_on_release

    RW

    设置是否执行 release_agent。为 1 时执行

    Tasks

    RW

    属于分组的线程 TID 列表

    Cgroup.procs

    R

    属于分组的进程 PID 列表。仅包括多线程进程的线程 leader 的 TID,这点与 tasks 不同

    Cgroup.event_control

    RW

    监视状态变化和分组删除事件的配置文件

    CGroup 相关概念解释
    1)任务(task)。在 cgroups 中,任务就是系统的一个进程;
    2)控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制;
    3)层级(hierarchy)。控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性;
    4)子系统(subsystem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

    相互关系
    1)每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup,此 cgroup 在创建层级时自动创建,后面在该层级中创建的 cgroup 都是此 cgroup 的后代)的初始成员;
    2)一个子系统最多只能附加到一个层级;
    3)一个层级可以附加多个子系统;
    4)一个任务可以是多个 cgroup 的成员,但是这些 cgroup 必须在不同的层级;
    5)系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不同的 cgroup 中,但开始时它总是继承其父任务的 cgroup。

    CGroup 介绍

    CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。

    转自:

    主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。

    图 1. CGroup 层级图

    图 1 所示的 CGroup 层级关系显示,CPU 和 Memory 两个子系统有自己独立的层级系统,而又通过 Task Group 取得关联关系。

    CGroup 特点
    在 cgroups 中,任务就是系统的一个进程。
    控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制。
    层级(hierarchy)。控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。
    子系统(subsytem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

    子系统的介绍
    blkio -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)。
    cpu -- 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。
    cpuacct -- 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。
    cpuset -- 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
    devices -- 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。
    freezer -- 这个子系统挂起或者恢复 cgroup 中的任务。
    memory -- 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。
    net_cls -- 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。

    CGroup 功能及组成

    CGroup 是将任意进程进行分组化管理的 Linux 内核功能。CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 CGroup 子系统或控制器。CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。

    CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用 CGroup,必须挂载 CGroup 文件系统。这时通过挂载选项指定使用哪个子系统。

    Cgroups提供了以下功能:
        1.限制进程组可以使用的资源数量(Resource limiting )。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
        2.进程组的优先级控制(Prioritization )。比如:可以使用cpu子系统为某个进程组分配特定cpu share。
        3.记录进程组使用的资源数量(Accounting )。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
        4.进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
        5.进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。

    很多时候需要测试程序在资源受限情况下的表现,普通的做法可能是不断对系统加压使能够分配给目标程序的资源变少,换另一个思路思考,可以尝试限制分配给目标程序的资源总数,使得机器状态健康的情况下让程序资源使用达到饱和。

    主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。

     

    图 2. CGroup 典型应用架构图

    如图 2 所示,CGroup 技术可以被用来在操作系统底层限制物理资源,起到 Container 的作用。图中每一个 JVM 进程对应一个 Container Cgroup 层级,通过 CGroup 提供的各类子系统,可以对每一个 JVM 进程对应的线程级别进行物理限制,这些限制包括 CPU、内存等等许多种类的资源。下一部分会具体对应用程序进行 CPU 资源隔离进行演示。

    cgroup的安装
    其实安装很简单,最佳实践就是yum直接安装(centos下)

    配置文件

    1 2 3 4 5 6 7 8 9 10 [[email protected] ~]# vim /etc/cgconfig.conf mount {          cpuset  = /cgroup/cpuset;                           cpu     =/cgroup/cpu;                           cpuacct =/cgroup/cpuacct;                           memory  =/cgroup/memory;                           devices =/cgroup/devices;                           freezer =/cgroup/freezer;                           net_cls =/cgroup/net_cls;                           blkio   =/cgroup/blkio;                                      }

    cgroup section的语法格式如下:
    group <name> { 
         [<permissions>] 
         <controller> { 
            <param name> = <param value>; 
            … 
         } 
    新葡亰496net:Cgroup和Namespace在测试中的使用,Linux资源控制。      …}

    其中:
    name: 指定cgroup的名称
    permissions:可选项,指定cgroup对应的挂载点文件系统的权限,root用户拥有所有权限。
    controller:子系统的名称
    param name 和 param value:子系统的属性及其属性值

    CGroup 支持的文件种类

    作为一个正在做着容器项目的人,知道容器技术是依靠Cgroup和Namespace来实现的。在容器中,cpu和内存资源是使用Cgroup来控制,PID、IPC、网络等资源是通过Namespace来划分。在程序没有部署在容器的情况下,我们仍可以利用Cgoup和Namespace来构造场景完成一些异常测试,如利用Cgroup的资源控制功能做资源满载的测试;利用Namespace的资源隔离特性做一些网络异常测试而不影响其他程序的运行。

     

    CPU资源控制

    每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.

    Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.

    Linux的调度策略可以参见代码: include/linux/sched.h

    /*
     * Scheduling policies
     */
    #define SCHED_NORMAL        0
    #define SCHED_FIFO        1
    #define SCHED_RR        2
    #define SCHED_BATCH        3
    /* SCHED_ISO: reserved but not implemented yet */
    #define SCHED_IDLE        5
    /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
    #define SCHED_RESET_ON_FORK     0x40000000
    

     

    Linux 系统也提供了修改调度策略的命令和系统调用接口.

    调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.

    # 在一个终端中执行
    sleep 1000
    # 打开另一个终端
    ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
    chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
          pid 1234's current scheduling policy: SCHED_OTHER
          pid 1234's current scheduling priority: 0
    
    chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
    chrt -p 1234         # 再次查看调度策略
          pid 1234's current scheduling policy: SCHED_FIFO
          pid 1234's current scheduling priority: 10
    

     

    补充:

    1. chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
    2. 查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<PID>/sched

     

    1.配置对mysql实例的资源限制

    1.1 修改cgconfig.conf文件

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 mount      cpuset  =/cgroup/cpuset     cpu =/cgroup/cpu     cpuacct =/cgroup/cpuacct     memory  =/cgroup/memory     blkio   =/cgroup/blkio     group mysql_g1 {        cpu {              cpu.cfs_quota_us = 50000;              cpu.cfs_period_us = 100000;           cpuset {                cpuset.cpus ="3";                cpuset.mems ="0";        }        cpuacct{               memory {                memory.limit_in_bytes=104857600;              memory.swappiness=0;              # memory.max_usage_in_bytes=104857600;              # memory.oom_control=0;      }       blkio  {             blkio.throttle.read_bps_device="8:0 524288"            blkio.throttle.write_bps_device="8:0 524288"     }   }

    1.2 配置文件的部分解释
    cpu:cpu使用时间限额

    cpu.cfs_period_us和cpu.cfs_quota_us来限制该组中的所有进程在单位时间里可以使用的cpu时间。这里的cfs是完全公平调度器的缩写。cpu.cfs_period_us就是时间周期(微秒),默认为100000,即百毫秒。cpu.cfs_quota_us就是在这期间内可使用的cpu时间(微秒),默认-1,即无限制。(cfs_quota_us是cfs_period_us的两倍即可限定在双核上完全使用)。
    cpuset:cpu绑定
    我们限制该组只能在0一共1个超线程上运行。cpuset.mems是用来设置内存节点的。
    本例限制使用超线程0上的第四个cpu线程。
    其实cgconfig也就是帮你把配置文件中的配置整理到/cgroup/cpuset这个目录里面,比如你需要动态设置mysql_group1/ cpuset.cpus的CPU超线程号,可以采用如下的办法。
    [[email protected] ~]# echo "0" > mysql_group1/ cpuset.cpus
    cpuacct:cpu资源报告
    memory:内存限制
     
    内存限制我们主要限制了MySQL可以使用的内存最大大小memory.limit_in_bytes=256M。而设置swappiness为0是为了让操作系统不会将MySQL的内存匿名页交换出去。
    blkio:BLOCK IO限额
    blkio.throttle.read_bps_device="8:0 524288"; #每秒读数据上限
    blkio.throttle.write_bps_device="8:0 524288"; #每秒写数据上限
    其中8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看
    [[email protected] ~]# ls -l /dev/sda 
    brw-rw----. 1 root disk 8, 0 Sep 15 04:19 /dev/sda

    1.3 拓展知识
    现在较新的服务器CPU都是numa结构<非一致内存访问结构(NUMA:Non-Uniform Memory Access)>,使用numactl --hardware可以看到numa各个节点的CPU超线程号,以及对应的节点号。

    本例结果如下:
    [[email protected] ~]# numactl --hardware 
    available: 1 nodes (0) 
    node 0 cpus: 0 1 2 3 
    node 0 size: 1023 MB 
    node 0 free: 68 MB 
    node distances: 
    node 0 
    0: 10 
    以下是较高端服务器的numa信息,仅作参考
    [[email protected] ~]# numactl --hardware 
    available: 4 nodes (0-3) 
    node 0 cpus: 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 
    node 0 size: 16338 MB 
    node 0 free: 391 MB 
    node 1 cpus: 1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 
    node 1 size: 16384 MB 
    node 1 free: 133 MB 
    node 2 cpus: 2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62 
    node 2 size: 16384 MB 
    node 2 free: 137 MB 
    node 3 cpus: 3 7 11 15 19 23 27 31 35 39 43 47 51 55 59 63 
    node 3 size: 16384 MB 
    node 3 free: 186 MB 
    node distances: 
    node 0 1 2 3 
    0: 10 20 30 20 
    1: 20 10 20 30 
    2: 30 20 10 20 
    3: 20 30 20 10

    1.4 修改cgrules.conf文件
    [[email protected] ~]# vim /etc/cgrules.conf 
    # /etc/cgrules.conf 
    #The format of this file is described in cgrules.conf(5) 
    #manual page. 

    # Example: 
    #<user> <controllers> <destination> 
    #@student cpu,memory usergroup/student/ 
    #peter cpu test1/ 
    #% memory test2/ 
    *:/usr/local/mysql/bin/mysqld * mysql_g1 
    注:共分为3个部分,分别为需要限制的实例,限制的内容(如cpu,memory),挂载目标。

    表 1. CGroup 支持的文件种类
    文件名 R/W 用途

    Release_agent

    RW

    删除分组时执行的命令,这个文件只存在于根分组

    Notify_on_release

    RW

    设置是否执行 release_agent。为 1 时执行

    Tasks

    RW

    属于分组的线程 TID 列表

    Cgroup.procs

    R

    属于分组的进程 PID 列表。仅包括多线程进程的线程 leader 的 TID,这点与 tasks 不同

    Cgroup.event_control

    RW

    监视状态变化和分组删除事件的配置文件

    Cgroup介绍

    Cgroup是进行分组化管理的Linux内核功能,具体的资源管理是通过子系统来完成的。可以理解为子系统就是资源控制器,每种子系统就是一个资源的分配器,比如cpu子系统是控制cpu时间分配的,使用方式如下

    CPU资源控制

    每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.

    Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.

    Linux的调度策略可以参见代码: include/linux/sched.h

    新葡亰496net 1

    /*
     * Scheduling policies
     */
    #define SCHED_NORMAL        0
    #define SCHED_FIFO        1
    #define SCHED_RR        2
    #define SCHED_BATCH        3
    /* SCHED_ISO: reserved but not implemented yet */
    #define SCHED_IDLE        5
    /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
    #define SCHED_RESET_ON_FORK     0x40000000
    

    新葡亰496net 2

     

    Linux 系统也提供了修改调度策略的命令和系统调用接口.

    调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.

    新葡亰496net 3

    # 在一个终端中执行
    sleep 1000
    # 打开另一个终端
    ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
    chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
          pid 1234's current scheduling policy: SCHED_OTHER
          pid 1234's current scheduling priority: 0
    
    chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
    chrt -p 1234         # 再次查看调度策略
          pid 1234's current scheduling policy: SCHED_FIFO
          pid 1234's current scheduling priority: 10
    

    新葡亰496net 4

     

    补充:

    1. chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
    2. 查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<PID>/sched

     

    实时进程的CPU控制

    所谓的实时进程, 也就是那些对响应时间要求比较高的进程.

    这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.

    在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.

    因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.

     

    所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.

     

    2 使配置生效

    [[email protected] ~]# /etc/init.d/cgconfig restart 
    Stopping cgconfig service: [ OK ] 
    Starting cgconfig service: [ OK ] 
    [[email protected] ~]# /etc/init.d/cgred restart 
    Stopping CGroup Rules Engine Daemon... [ OK ] 
    Starting CGroup Rules Engine Daemon: [ OK ] 
    注:重启顺序为cgconfig -> cgred ,更改配置文件后两个服务需要重启,且顺序不能错。

    CGroup 相关概念解释

    1. 任务(task)。在 cgroups 中,任务就是系统的一个进程;

    2. 控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制;

    3. 层级(hierarchy)。控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性;

    4. 子系统(subsystem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

    相互关系

    1. 每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup,此 cgroup 在创建层级时自动创建,后面在该层级中创建的 cgroup 都是此 cgroup 的后代)的初始成员;

    2. 一个子系统最多只能附加到一个层级;

    3. 一个层级可以附加多个子系统;

    4. 一个任务可以是多个 cgroup 的成员,但是这些 cgroup 必须在不同的层级;

    5. 系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不同的 cgroup 中,但开始时它总是继承其父任务的 cgroup。

    安装(ubuntu)

    #apt-get install cgroup-bin

    实时进程的CPU控制

    所谓的实时进程, 也就是那些对响应时间要求比较高的进程.

    这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.

    在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.

    因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.

     

    所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.

     

    系统整体设置

    1. 获取当前系统的设置

      sysctl -n kernel.sched_rt_period_us # 实时进程调度的单位CPU时间 1 秒 1000000 sysctl -n kernel.sched_rt_runtime_us # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒 950000

    这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.

    这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.

     

    1. 设置实时进程占用CPU时间

    上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:

    sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
    kernel.sched_rt_runtime_us = 900000
    sysctl -n kernel.sched_rt_runtime_us 
    900000
    

     

    3 启动MySQL,查看MySQL是否处于cgroup的限制中

    [[email protected] ~]# ps -eo pid,cgroup,cmd | grep -i mysqld 
    29871 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/ /bin/sh ./bin/mysqld_safe --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/
    30219 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/mysql_g1 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/ --plugin-dir=/usr/local/mysql//lib/plugin --user=mysql --log-error=/usr/local/mysql/data//localhost.localdomain.err --pid-file=/usr/local/mysql/data//localhost.localdomain.pid --socket=/tmp/mysql.sock --port=3306
    30311 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/ grep -i mysqld

    图 1. CGroup 层级图

    基本命令

    cgclassify -- cgclassify命令是用来将运行的任务移动到一个或者多个cgroup。

    cgclear -- cgclear 命令是用来删除层级中的所有cgroup。

    cgconfig.conf -- 在cgconfig.conf文件中定义cgroup。

    cgconfigparser -- cgconfigparser命令解析cgconfig.conf文件和并挂载层级。

    cgcreate -- cgcreate在层级中创建新cgroup。

    cgdelete -- cgdelete命令删除指定的cgroup。

    cgexec -- cgexec命令在指定的cgroup中运行任务。

    cgget -- cgget命令显示cgroup参数。

    cgred.conf -- cgred.conf是cgred服务的配置文件。

    cgrules.conf -- cgrules.conf 包含用来决定何时任务术语某些 cgroup的规则。

    cgrulesengd -- cgrulesengd 在 cgroup 中发布任务。

    cgset -- cgset 命令为 cgroup 设定参数。

    lscgroup -- lscgroup 命令列出层级中的 cgroup。

    lssubsys -- lssubsys 命令列出包含指定子系统的层级

    系统整体设置

    1. 获取当前系统的设置

      sysctl -n kernel.sched_rt_period_us # 实时进程调度的单位CPU时间 1 秒 1000000 sysctl -n kernel.sched_rt_runtime_us # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒 950000

    这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.

    这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.

     

    1. 设置实时进程占用CPU时间

    上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:

    sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
    kernel.sched_rt_runtime_us = 900000
    sysctl -n kernel.sched_rt_runtime_us 
    900000
    

     

    cgroup 中的设置

    整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.

    如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y

    查看当前系统的内核编译选项方法如下: (debian 7.6 系统)

    cat /boot/config-`uname -r`
    

    查看 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    # CONFIG_RT_GROUP_SCHED is not set
    

    debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件

    mkdir /mnt/cgroup
    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
    --w------- 1 root root 0 Aug 28 09:06 devices.allow
    --w------- 1 root root 0 Aug 28 09:06 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
    

     

    果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us

    没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核

    为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y

    下载源码等等参见: 编译Linux内核, 主要步骤如下:

    cd /path/to/linux-source-3.2
    make localmodconfig
    vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
    make
    make modules_install
    make install
    reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
    
     
    

    启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    CONFIG_RT_GROUP_SCHED=y       # 已启用
    

     

    再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us

    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
    --w------- 1 root root 0 Aug 28 09:53 devices.allow
    --w------- 1 root root 0 Aug 28 09:53 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
    
    cat cpu.rt_period_us 
    1000000
    cat cpu.rt_runtime_us 
    950000
    

     

    通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.

     

    4 资源限制验证

    使用mysqlslap对mysql进行压力测试,看mysql使用资源是否超过限制

    4.1 在shell窗口1用mysqlslap对mysql进行压力测试
    [[email protected] ~]# /usr/local/mysql/bin/mysqlslap --defaults-file=/etc/my.cnf --concurrency=150 --iterations=1 --number-int-cols=8 --auto-generate-sql --auto-generate-sql-load-type=mixed --engine=innodb --number-of-queries=100000 -ujesse -pjesse --number-char-cols=35 --auto-generate-sql-add-autoincrement --debug-info -P3306 -h127.0.0.1

    4.2 在shell窗口2查看mysql对cpu,内存的使用

    可见:cpu限制在了第四个核心上,且对第四个核心的使用限制在50%。

    4.3 在shell窗口3查看io的消耗

    可见:mysql对io的读及写消耗均限制在2M每秒以内。

    新葡亰496net 5

    图 1 所示的 CGroup 层级关系显示,CPU 和 Memory 两个子系统有自己独立的层级系统,而又通过 Task Group 取得关联关系。

    子系统说明

    可以使用lssubsys -a来列出系统支持多少种子系统,和:比如cpu是控制cpu时间片的,memory是控制内存使用的

    #lssubsys -a

    cpuset

    cpu,cpuacct

    memory

    devices

    freezer

    net_cls,net_prio

    blkio

    perf_event

    hugetlb

    主要的几种子系统说明如下:

    blkio 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等。

    cpu 这个子系统使用调度程序为cgroup任务提供cpu的访问。

    cpuacct 产生cgroup任务的cpu资源报告。

    cpuset 如果是多核心的cpu,这个子系统会为cgroup任务分配单独的cpu和内存。

    devices 允许或拒绝cgroup任务对设备的访问。

    freezer 暂停和恢复cgroup任务。

    memory 设置每个cgroup的内存限制以及产生内存资源报告。

    net_cls 标记每个网络包以供cgroup方便使用。

    ns 名称空间子系统

    perf_event: 增加了对每group的监测跟踪的能力,即可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程

    要为Cgroup分配限制的资源,首先要挂载子系统,然后才有控制组,比如想要对目标程序进行内存限制,那就需要挂载memory子系统

    使用lssubsys -am来显示已经挂载的子系统

    #lssubsys -am

    cpuset /sys/fs/cgroup/cpuset

    cpu,cpuacct /sys/fs/cgroup/cpu,cpuacct

    memory /sys/fs/cgroup/memory

    devices /sys/fs/cgroup/devices

    freezer /sys/fs/cgroup/freezer

    net_cls,net_prio /sys/fs/cgroup/net_cls,net_prio

    blkio /sys/fs/cgroup/blkio

    perf_event /sys/fs/cgroup/perf_event

    hugetlb /sys/fs/cgroup/hugetlb

    可以手动挂载或者卸载子系统,如执行umount /sys/fs/cgroup/memory,memory子系统就被卸载了,这时候手动执行# mount -t cgroup -o memory memory /sys/fs/cgroup/memory就又挂载上了。
    要确保需要的子系统都挂上了,不然创建控制组的时候会报错 is not mounted

    #cgcreate -g memory,cpu:/hzmali_test

    cgcreate: can't create cgroup /hzmali_test: Cgroup one of the needed subsystems is not mounted

    如何创建control group(即需要资源管理的组)呢, 这里用cgcreate命令,当然也有其他方法, 如cgconfig.conf等

    #cgcreate -g memory,cpu:/hzmali_test

    这里有个重要特性:一个组可以同时做多个资源的限制,如这里我同时限制了memory和cpu,然后memory和cpu子系统目录下会自动生成这个组的目录和些文件,如memory

    #/sys/fs/cgroup/memory/hzmali_test$ ls -lrt

    -rw-r--r-- 1 root root 0 Jul 26 20:56 tasks

    -rw-r--r-- 1 root root 0 Jul 26 20:56 notify_on_release

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.use_hierarchy

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.usage_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.swappiness

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.stat

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.soft_limit_in_bytes

    ---------- 1 root root 0 Jul 26 20:56 memory.pressure_level

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.oom_control

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.numa_stat

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.move_charge_at_immigrate

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.max_usage_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.limit_in_bytes

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.usage_in_bytes

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.tcp.usage_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.tcp.max_usage_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.tcp.limit_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.tcp.failcnt

    -r--r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.slabinfo

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.max_usage_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.limit_in_bytes

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.kmem.failcnt

    --w------- 1 root root 0 Jul 26 20:56 memory.force_empty

    -rw-r--r-- 1 root root 0 Jul 26 20:56 memory.failcnt

    -rw-r--r-- 1 root root 0 Jul 26 20:56 cgroup.procs

    --w--w--w- 1 root root 0 Jul 26 20:56 cgroup.event_control

    -rw-r--r-- 1 root root 0 Jul 26 20:56 cgroup.clone_children

    文件很多,选几个重要的讲下:

    • tasks 可以将想要限制资源的进程都加到这个文件中
    • memory.max_usage_in_bytes内存的最大使用量,用来限制资源
      -memory.soft_limit_in_bytes 和 memory.limit_in_bytes 的差异是,这个限制并不会阻止进程使用超过限额的内存,只是在系统内存不足时,会优先回收超过限额的进程占用的内存,使之向限定值靠拢。
    • memory.oom_control
      包含一个标志(0或1)来开启或者关闭cgroup的OOM killer。如果开启(1),任务如果尝试申请内存超过允许,就会被系统OOM killer终止。OOM killer在每个使用cgroup内存子系统中都是默认开启的。如果需要关闭,则可以向memory.oom_control文件写入1:

    # echo 1 > /sys/fs/cgroup/memory.oom_control
    如果OOM killer关闭,那么进程尝试申请的内存超过允许,那么它就会被暂停,直到额外的内存被释放

    • memory.mem.usage_in_bytes 当前进程内存用量,因为现在还没有进程加到组里,就是0了
    • memory.mem.failcnt显示内存达到限制值的次数

    cgroup 中的设置

    整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.

    如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y

    查看当前系统的内核编译选项方法如下: (debian 7.6 系统)

    cat /boot/config-`uname -r`
    

    查看 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    # CONFIG_RT_GROUP_SCHED is not set
    

    debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件

    新葡亰496net 6

    mkdir /mnt/cgroup
    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
    --w------- 1 root root 0 Aug 28 09:06 devices.allow
    --w------- 1 root root 0 Aug 28 09:06 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
    

    新葡亰496net 7

     

    果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us

    没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核

    为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y

    下载源码等等参见: 编译Linux内核, 主要步骤如下:

    新葡亰496net 8

    cd /path/to/linux-source-3.2
    make localmodconfig
    vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
    make
    make modules_install
    make install
    reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
    

    新葡亰496net 9

     
    

    启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    CONFIG_RT_GROUP_SCHED=y       # 已启用
    

     

    再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us

    新葡亰496net 10

    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
    --w------- 1 root root 0 Aug 28 09:53 devices.allow
    --w------- 1 root root 0 Aug 28 09:53 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
    
    cat cpu.rt_period_us 
    1000000
    cat cpu.rt_runtime_us 
    950000
    

    新葡亰496net 11

     

    通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.

     

    资源控制实例

    上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.

    Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory

     

    cgroup实例分析(手工动态验证)

    还原配置文件/etc/cgconfig.conf及/etc/cgrules.conf 为默认配置。测试实例依然为mysql,测试工具为mysqlslap。

    开启cgconfig及cgrules 服务
    [[email protected] ~]# /etc/init.d/cgconfig restart 
    Stopping cgconfig service: [ OK ] 
    Starting cgconfig service: [ OK ] 
    [[email protected] /]# /etc/init.d/cgred restart 
    Stopping CGroup Rules Engine Daemon... [ OK ] 
    Starting CGroup Rules Engine Daemon: [ OK ]

    开启mysqlslap压力测试程序
    [[email protected] /]# /usr/local/mysql/bin/mysqlslap --defaults-file=/etc/my.cnf --concurrency=150 --iterations=1 --number-int-cols=8 --auto-generate-sql --auto-generate-sql-load-type=mixed --engine=innodb --number-of-queries=100000 -ujesse -pjesse --number-char-cols=35 --auto-generate-sql-add-autoincrement --debug-info -P3306 -h127.0.0.1

    通过htop查看资源消耗。

    CGroup 特点

    在 cgroups 中,任务就是系统的一个进程。

    控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制。

    层级(hierarchy)。控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。

    子系统(subsytem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

    Cgroup文档

    Cgroup的使用细节,子系统和参数设置都可以可以在中找到,继承等特性由于篇幅所限,可以看下文档

    资源控制实例

    上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.

    Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory

     

    实例: cgroup 中对其中 *子cgroup* 的CPU资源控制

    对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件

    直接用实验过程来说话, 其中加入了一些注释.

    # 安装需要的软件
    apt-get install stress     # 让CPU达到 100% 的压力工具
    apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
    

     

    1)cpu限制实例

    限制mysql使用一个核,如第2个核,且对该核的使用不超过50%
    [[email protected] ~]# mkdir -p /cgroup/cpu/foo/ 
    [[新葡亰496net:Cgroup和Namespace在测试中的使用,Linux资源控制。email protected] ~]# mkdir -p /cgroup/cpuset/foo/ 
    [[email protected] ~]# echo 50000 > /cgroup/cpu/foo/cpu.cfs_quota_us 
    [[email protected] ~]# echo 100000 > /cgroup/cpu/foo/cpu.cfs_period_us 
    [[email protected] ~]# echo "0" > /cgroup/cpuset/foo/cpuset.mems 
    [[email protected] ~]# echo "1" > /cgroup/cpuset/foo/cpuset.cpus 
    [[email protected] ~]# echo 28819 > /cgroup/cpu/foo/tasks

    其中:28819为mysqld的进程号。

    子系统的介绍

    blkio   -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)。
    cpu     -- 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。
    cpuacct -- 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。
    cpuset  -- 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
    devices -- 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。

    freezer -- 这个子系统挂起或者恢复 cgroup 中的任务。
    memory  -- 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。
    net_cls -- 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。

    CGroup 应用架构

    Cgroup实战

    实例: cgroup 中对其中 *子cgroup* 的CPU资源控制

    对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件

    直接用实验过程来说话, 其中加入了一些注释.

    # 安装需要的软件
    apt-get install stress     # 让CPU达到 100% 的压力工具
    apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
    

     

    实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
    1. 挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
    2. 在 cgroup中创建 2个子cgroup A 和 B
    3. 默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
    4. 在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%
    5. top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)

     

    # 挂载 cgroup 文件系统
    mount -t cgroup -o cpu cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares
    --w------- 1 root root 0 Aug 28 11:29 devices.allow
    --w------- 1 root root 0 Aug 28 11:29 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
    
    # 创建 子cgroup A 和 B
    mkdir {A,B}
    cat A/cpu.shares 
    1024
    cat B/cpu.shares 
    1024
    
    # 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
    echo $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中
    stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
    # 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中
    echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
    stress -c 2    # 在2个核上都产生 100% 的CPU 占用率
    # 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
    top
    top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       
    3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       
    3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
    3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3349
    3350   <-- stress 进程
    3351   <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3352
    3353   <-- stress 进程
    3354   <-- stress 进程
    

    可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,

    由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2

     

    2) 内存限制实例

    限制mysql使用内存为不超过512M
    跑一个消耗内存脚本

    1 2 3 4 #!/bin/bash<br>x='a'  while [ True ];do      x=$x$x  done;

    内存的消耗在不断增加,对其进行限制,使其使用内存在500M以内
    [[email protected] ~]# mkdir -p /cgroup/memory/foo 
    [[email protected] ~]# echo 524288000 > /cgroup/memory/foo/memory.limit_in_bytes 
    [[email protected] ~]# echo 44476 > /cgroup/memory/foo/tasks

    内存使用得到了有效控制。

    图 2. CGroup 典型应用架构图

    内存限制测试

    用控制组限制目标程序内存使用为1000000 byte,当然,需要root执行
    echo "1000000" >memory.limit_in_bytes

    一般更推荐用cgset来设置数值

    cgset -r memory.limit_in_bytes=1000000 hzmali_test

    然后构造一个吃内存的程序,每运行一次内存使用就大幅增加

    #vim memtest.sh

    x="hahaha"

    while [ True ];do

    x=$x$x$x$x$x$x$x$x$x$x

    sleep 1

    done;

    然后运行程序,并将进程pid写入mem下面控制组的tasks中

    #./memtest.sh &

    [1] 17638

    # echo 17638 > /sys/fs/cgroup/memory/hzmali_test/tasks

    使用cgclassify 可以将运行中的进程加到task中,如果控制组有多个资源的控制,使用命令会比echo方便很多

    cgclassify -g mem:hzmali_test 17638

    然后这货就在不断占内存,由于没有设置disable oom killing,所以最后会oom被kill掉

    # cat /sys/fs/cgroup/memory/hzmali_test/memory.usage_in_bytes

    966656

    # cat /sys/fs/cgroup/memory/hzmali_test/memory.usage_in_bytes

    978944

    # cat /sys/fs/cgroup/memory/hzmali_test/memory.usage_in_bytes

    995328

    #

    [1] Killed ./memtest.sh

    实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
    1. 挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
    2. 在 cgroup中创建 2个子cgroup A 和 B
    3. 默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
    4. 在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%
    5. top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)

     

    新葡亰496net 12

    # 挂载 cgroup 文件系统
    mount -t cgroup -o cpu cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares
    --w------- 1 root root 0 Aug 28 11:29 devices.allow
    --w------- 1 root root 0 Aug 28 11:29 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
    
    # 创建 子cgroup A 和 B
    mkdir {A,B}
    cat A/cpu.shares 
    1024
    cat B/cpu.shares 
    1024
    
    # 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
    echo $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中
    stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
    # 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中
    echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
    stress -c 2    # 在2个核上都产生 100% 的CPU 占用率
    # 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
    top
    top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       
    3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       
    3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
    3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3349
    3350   <-- stress 进程
    3351   <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3352
    3353   <-- stress 进程
    3354   <-- stress 进程
    

    新葡亰496net 13

    可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,

    由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2

     

    实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
    1. 环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
    2. A group 的 cpu.shares 文件不变, 值为 1024
    3. B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512 1024) = 1/3)
    4. 同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况

     

    # 在 B 中shell 窗口执行以下命令
    cat B/cpu.shares 
    1024
    echo 512 > B/cpu.shares 
    cat B/cpu.shares 
    512
    stress -c 2
    
    # 在 A 中 shell 窗口执行以下命令
    stress -c 2
    
    # 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
    top
    top - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
    3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       
    3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
    3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3375
    3376    <-- stress 进程
    3377    <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3372
    3373    <-- stress 进程
    3374    <-- stress 进程
    

    很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.

     

    3)IO限制实例

    跑一个消耗IO的测试
    [[email protected] ~]# dd if=/dev/sda of=/dev/null 
    通过iotop看io占用情况,磁盘读取速度到了50M/s

     
    限制读取速度为10M/S

    [[email protected] ~]# mkdir -p /cgroup/blkio/foo 
    [[email protected] ~]# echo '8:0 10485760' > /cgroup/blkio/foo/blkio.throttle.read_bps_device
    [[email protected] ~]# echo 45033 > /cgroup/blkio/foo/tasks 
    注1:45033为dd的进程号
    注2:8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看
    [[email protected] ~]# ls -l /dev/sda 
    brw-rw----. 1 root disk 8, 0 Sep 15 04:19 /dev/sda

    新葡亰496net 14

    如图 2 所示,CGroup 技术可以被用来在操作系统底层限制物理资源,起到 Container 的作用。图中每一个 JVM 进程对应一个 Container Cgroup 层级,通过 CGroup 提供的各类子系统,可以对每一个 JVM 进程对应的线程级别进行物理限制,这些限制包括 CPU、内存等等许多种类的资源。下一部分会具体对应用程序进行 CPU 资源隔离进行演示。

    CPU限制测试

    我的机器上有2个核

    %Cpu0 : 0.0 us, 0.3 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

    %Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

    写个死循环脚本cpu_test.sh跑一下

    x=a

    while [ True ];do

    x=$x

    done;

    如果我不想把机器跑死,这里想要限制组里的进程的CPU使用,有2种做法
    1.在cpu子系统中控制cpu调度的配额
    先看下当前cpu分配情况

    cat /sys/fs/cgroup/cpu/hzmali_test/cpu.cfs_quota_us

    -1

    cat /sys/fs/cgroup/cpu/hzmali_test/cpu.cfs_period_us

    100000

    -1表示无限制,这里改为50000,即相对于cpu.cfs_period_us 来说为50000/100000约占1个核50%的cpu时间

    #./cpu_test.sh &

    [1] 17709

    # echo 17709 >/sys/fs/cgroup/cpu/hzmali_test/tasks

    或者直接使用命令cgexec执行

    cgexec -g cpu:hzmali_test ./cpu_test.sh

    top了下基本上就是在50%的cpu占用

    %Cpu0 : 50.5 us, 0.0 sy, 0.0 ni, 49.5 id, 0.0 wa, 0.0 hi, 0.0 si,0.0 st

    %Cpu1 : 0.0 us, 0.3 sy,0.0 ni, 99.7 id,0.0 wa, 0.0 hi,0.0 si, 0.0 st

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND17709 root 20 0 25368 20201764 R 50.2 0.1 1:14.74 bash

    2.在cpuset控制物理cpu的分配
    当前使用了上面的方法后,我们发现进程的CPU使用都在Cpu0上,这次希望只用Cpu1来跑这个小程序
    所以把控制组也加到cpuset

    # cgcreate -g cpuset:/hzmali_test

    看一下现在使用的cpu的设置

    # cat /sys/fs/cgroup/cpuset/hzmali_test/cpuset.cpus

    0-1

    改为只用Cpu1,输入以下命令

    # echo 1 > /sys/fs/cgroup/cpuset/hzmali_test/cpuset.cpus

    # echo 17709 > /sys/fs/cgroup/cpuset/hzmali_test/tasks

    或用命令

    # cgset -r cpuset.cpus='1' hzmali_test

    # cgclassify -g cpu,cpuset:hzmali_test 17709

    top一下,内存的使用从CPU0到CPU1了

    %Cpu0 : 0.0 us, 0.0 sy,0.0 ni, 99.7 id,0.0 wa, 0.0 hi,0.3 si, 0.0 st

    %Cpu1 : 50.3 us, 0.0 sy, 0.0 ni, 49.7 id, 0.0 wa, 0.0 hi, 0.0 si,0.0 st

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND

    17709 root 200 25368 2108 2076 R 50.10.1 8:56.78 bash

    实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
    1. 环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
    2. A group 的 cpu.shares 文件不变, 值为 1024
    3. B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512 1024) = 1/3)
    4. 同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况

     

    新葡亰496net 15

    # 在 B 中shell 窗口执行以下命令
    cat B/cpu.shares 
    1024
    echo 512 > B/cpu.shares 
    cat B/cpu.shares 
    512
    stress -c 2
    
    # 在 A 中 shell 窗口执行以下命令
    stress -c 2
    
    # 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
    top
    top - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
    3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       
    3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
    3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3375
    3376    <-- stress 进程
    3377    <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3372
    3373    <-- stress 进程
    3374    <-- stress 进程
    

    新葡亰496net 16

    很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.

     

    实例3 - 物理CPU的控制

    上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.

    要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.

    首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y

    cat /boot/config-`uname -r` | grep -i cpusets
    CONFIG_CPUSETS=y
    

    我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......

     

    然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况

    1. 卸载当前的 cgroup
    2. 再次挂载 cgroup 文件系统, 并指定 -o cpuset
    3. 指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
    4. 指定 B 的物理CPU也为 0
    5. 重复 实例1 中的步骤, 观察发生的变化

     

    umount /mnt/cgroup
    mount -t cgroup -o cpuset cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 14:39 tasks
    
    # 创建子cgroup A 和 B
    mkdir {A,B}
    cat A/cpuset.cpus   
             <--  默认是空的
    echo 0 > A/cpuset.cpus
    cat A/cpuset.cpus 
    0
    echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0
    # 当前Shell加入到 A组
    echo $$ > /mnt/cgroup/A/tasks 
    -bash: echo: write error: No space left on device
    

     

    如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: )

    # 同时设置 A 的 cpuset.cpus 和 cpuset.mems
    echo 0 > A/cpuset.cpus
    echo 0 > A/cpuset.mems
    # B组也同样设置
    echo 0 > B/cpuset.cpus
    echo 0 > B/cpuset.mems
    
    # 将当前 shell 加入到 A组
    echo $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
    stress -c 2
    
    # 再打开一个Shell窗口, 并加入到 B组
    echo $$ > /mnt/cgroup/B/tasks
    stress -c 2
    
    # 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
    top
    top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 50.0 us,  0.0 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
    3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
    3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
    3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
    

    从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,

    所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.

     

    如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.

    下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.

    # 在 B组的 shell 窗口中执行以下命令
    echo 1 > /mnt/cgroup/B/cpuset.cpus
    cat /mnt/cgroup/B/cpuset.cpus
    1
    stress -c 2
    
    # 在 A组的 shell 窗口中执行以下命令
    stress -c 2
    
    # 在第3个shell窗口中用top命令查看执行结果
    top
    top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
      PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
     3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
     3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
    

    果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.

     

    cgroup小结

    使用cgroup临时对进程进行调整,直接通过命令即可,如果要持久化对进程进行控制,即重启后依然有效,需要写进配置文件/etc/cgconfig.conf及/etc/cgrules.conf 

    ***************当你发现自己的才华撑不起野心时,就请安静下来学习吧***************

    ==================================================================

    ¥¥='$$'

     Linux资源控制-CPU和内存

    主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。
     
    CPU资源控制
    每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.
    Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.
    Linux的调度策略可以参见代码: include/linux/sched.h
    /*
     * Scheduling policies
     */
    #define SCHED_NORMAL        0
    #define SCHED_FIFO        1
    #define SCHED_RR        2
    #define SCHED_BATCH        3
    /* SCHED_ISO: reserved but not implemented yet */
    #define SCHED_IDLE        5
    /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
    #define SCHED_RESET_ON_FORK     0x40000000
     
    Linux 系统也提供了修改调度策略的命令和系统调用接口.
    调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.
    # 在一个终端中执行
    sleep 1000
    # 打开另一个终端
    ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
    chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
          pid 1234's current scheduling policy: SCHED_OTHER
          pid 1234's current scheduling priority: 0
    chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
    chrt -p 1234         # 再次查看调度策略
          pid 1234's current scheduling policy: SCHED_FIFO
          pid 1234's current scheduling priority: 10
     
    补充:
        chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
        查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<PID>/sched
     
    实时进程的CPU控制
    所谓的实时进程, 也就是那些对响应时间要求比较高的进程.
    这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.
    在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.
    因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.
     
    所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.
     
    系统整体设置

    1. 获取当前系统的设置
      sysctl -n kernel.sched_rt_period_us   # 实时进程调度的单位CPU时间 1 秒
      1000000
      sysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒
      950000
      这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.
      这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.  
    2. 设置实时进程占用CPU时间
      上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:
      sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
      kernel.sched_rt_runtime_us = 900000
      sysctl -n kernel.sched_rt_runtime_us 
      900000
       
      cgroup 中的设置
      整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.
      如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y
      查看当前系统的内核编译选项方法如下: (debian 7.6 系统)
      cat /boot/config-`uname -r`
      查看 CONFIG_RT_GROUP_SCHED 是否启用
      cat /boot/config-`uname -r` | grep -i rt_group
      # CONFIG_RT_GROUP_SCHED is not set
      debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件
      mkdir /mnt/cgroup
      mount -t cgroup cgroup /mnt/cgroup/
      cd /mnt/cgroup/
      ls -l
      total 0
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time
      --w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
      -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
      -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
      -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
      --w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
      -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
      -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
      -r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
      -rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
      --w------- 1 root root 0 Aug 28 09:06 devices.allow
      --w------- 1 root root 0 Aug 28 09:06 devices.deny
      -r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
      -rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
      -rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release
      -rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
      -rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
       
      果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us
      没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核
      为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y
      下载源码等等参见: 编译Linux内核, 主要步骤如下:
      cd /path/to/linux-source-3.2
      make localmodconfig
      vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
      make
      make modules_install
      make install
      reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
       
      启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用
      cat /boot/config-`uname -r` | grep -i rt_group
      CONFIG_RT_GROUP_SCHED=y       # 已启用
       
      再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us
      mount -t cgroup cgroup /mnt/cgroup/
      cd /mnt/cgroup/
      ls -l
      total 0
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
      --w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
      -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time
      -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight
      -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
      --w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
      -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
      -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
      -r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
      -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
      --w------- 1 root root 0 Aug 28 09:53 devices.allow
      --w------- 1 root root 0 Aug 28 09:53 devices.deny
      -r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
      -rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
      -rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
      -rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
      -rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
      cat cpu.rt_period_us 
      1000000
      cat cpu.rt_runtime_us 
      950000
       
      通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.
       
      资源控制实例
      上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.
      Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory
       
      实例: cgroup 中对其中 *子cgroup* 的CPU资源控制
      对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件
      直接用实验过程来说话, 其中加入了一些注释.
      # 安装需要的软件
      apt-get install stress     # 让CPU达到 100% 的压力工具
      apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
       
      实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
          挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
          在 cgroup中创建 2个子cgroup A 和 B
          默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
          在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%
          top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)
       
      # 挂载 cgroup 文件系统
      mount -t cgroup -o cpu cgroup /mnt/cgroup/
      cd /mnt/cgroup
      ls -l
      total 0
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
      --w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
      -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
      -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
      -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
      --w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
      -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
      -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
      -r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
      -rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares
      --w------- 1 root root 0 Aug 28 11:29 devices.allow
      --w------- 1 root root 0 Aug 28 11:29 devices.deny
      -r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
      -rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
      -rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release
      -rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
      -rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
      # 创建 子cgroup A 和 B
      mkdir {A,B}
      cat A/cpu.shares 
      1024
      cat B/cpu.shares 
      1024
      # 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
      echo ¥¥ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中
      stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
      # 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中
      echo ¥¥ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
      stress -c 2    # 在2个核上都产生 100% 的CPU 占用率
      # 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
      top
      top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
      Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
      %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
      KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers
      KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
       PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
      3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       
      3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       
      3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
      3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    
      # 查看这 4 个stress 进程是否分别属于 A 和 B
      cat /mnt/cgroup/A/tasks 
      2945
      3349
      3350   <-- stress 进程
      3351   <-- stress 进程
      cat /mnt/cgroup/B/tasks 
      2996
      3352
      3353   <-- stress 进程
      3354   <-- stress 进程
      可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,
      由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2
       
      实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
          环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
          A group 的 cpu.shares 文件不变, 值为 1024
          B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512 1024) = 1/3)
          同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况
       
      # 在 B 中shell 窗口执行以下命令
      cat B/cpu.shares 
      1024
      echo 512 > B/cpu.shares 
      cat B/cpu.shares 
      512
      stress -c 2
      # 在 A 中 shell 窗口执行以下命令
      stress -c 2
      # 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
      top
      top - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
      Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
      %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
      KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
      KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
       PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
      3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
      3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       
      3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
      3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               
      # 查看这 4 个stress 进程是否分别属于 A 和 B
      cat /mnt/cgroup/A/tasks 
      2945
      3375
      3376    <-- stress 进程
      3377    <-- stress 进程
      cat /mnt/cgroup/B/tasks 
      2996
      3372
      3373    <-- stress 进程
      3374    <-- stress 进程
      很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.
       
      实例3 - 物理CPU的控制
      上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.
      要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.
      首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y
      cat /boot/config-`uname -r` | grep -i cpusets
      CONFIG_CPUSETS=y
      我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......
       
      然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况
          卸载当前的 cgroup
          再次挂载 cgroup 文件系统, 并指定 -o cpuset
          指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
          指定 B 的物理CPU也为 0
          重复 实例1 中的步骤, 观察发生的变化
       
      umount /mnt/cgroup
      mount -t cgroup -o cpuset cgroup /mnt/cgroup/
      cd /mnt/cgroup
      ls -l
      total 0
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
      --w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
      -r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
      -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level
      -rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
      -rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
      -rw-r--r-- 1 root root 0 Aug 28 14:39 tasks
      # 创建子cgroup A 和 B
      mkdir {A,B}
      cat A/cpuset.cpus   
               <--  默认是空的
      echo 0 > A/cpuset.cpus
      cat A/cpuset.cpus 
      0
      echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0
      # 当前Shell加入到 A组
      echo ¥¥ > /mnt/cgroup/A/tasks 
      -bash: echo: write error: No space left on device
       
      如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: )
      # 同时设置 A 的 cpuset.cpus 和 cpuset.mems
      echo 0 > A/cpuset.cpus
      echo 0 > A/cpuset.mems
      # B组也同样设置
      echo 0 > B/cpuset.cpus
      echo 0 > B/cpuset.mems
      # 将当前 shell 加入到 A组
      echo ¥¥ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
      stress -c 2
      # 再打开一个Shell窗口, 并加入到 B组
      echo ¥¥ > /mnt/cgroup/B/tasks
      stress -c 2
      # 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
      top
      top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
      Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
      %Cpu(s): 50.0 us,  0.0 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
      KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
      KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
       PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
      3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
      3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
      3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
      3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
      从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,
      所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.
       
      如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.
      下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.
      # 在 B组的 shell 窗口中执行以下命令
      echo 1 > /mnt/cgroup/B/cpuset.cpus
      cat /mnt/cgroup/B/cpuset.cpus
      1
      stress -c 2
      # 在 A组的 shell 窗口中执行以下命令
      stress -c 2
      # 在第3个shell窗口中用top命令查看执行结果
      top
      top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
      Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
      %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
      KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
      KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
        PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
       3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
       3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
       3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
       3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
      果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.
       
      实例4 - cgroup 对使用的内存的控制
      cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory
      # 首先之前挂载的 cpuset 子系统
      umount /mnt/cgroup
      # 挂载cgroup 文件系统, 指定 -o memeory
      mount -o memory -t cgroup memcg /mnt/cgroup/
      mount: special device memcg does not exist
       
      出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:
      cat /proc/cgroups 
      #subsys_name    hierarchy    num_cgroups    enabled
      cpuset    0    1    1
      cpu    0    1    1
      cpuacct    0    1    1
      memory    1    1    0              <-- 这里的 enabled 是 0
      devices    0    1    1
      freezer    0    1    1
      net_cls    0    1    1
      blkio    0    1    1
      perf_event    0    1    1
       
      为了默认启用memory子系统, 可以设置 grub选项
      vim /etc/default/grub
      # 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
      # 保存后, 更新grub.cfg
      update-grub
      reboot
       
      重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了
      cat /proc/cgroups 
      #subsys_name    hierarchy    num_cgroups    enabled
      cpuset    0    1    1
      cpu    0    1    1
      cpuacct    0    1    1
      memory    1    1    1
      devices    0    1    1
      freezer    0    1    1
      net_cls    0    1    1
      blkio    0    1    1
      perf_event    0    1    1
      # 挂载cgroup 的memory子系统
      mount -t cgroup -o memory memcg /mnt/cgroup
      ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
      total 0
      -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
      --w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
      -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
      --w------- 1 root root 0 Aug 28 15:54 memory.force_empty
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
      -r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
      -r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
      -r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
      -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
      -rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
      -rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
      -rw-r--r-- 1 root root 0 Aug 28 15:54 tasks
       
      开始实验:
          重启系统 (为了保证内存的干净)
          挂载 memcg
          在挂载的 /mnt/cgroup 中创建 组A
          将当前shell 加入到 组A
          不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
          重复步骤 1 ~ 4
          限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化
       
      # 重启系统
      reboot
      # 挂载 memcg
      mount -t cgroup -o memory memcg /mnt/cgroup
      # 创建 组A
      mkdir /mnt/cgroup/A
      # 将当前 shell 加入到组A
      echo ¥¥ > /mnt/cgroup/A/tasks
      # 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
      free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                   total       used       free     shared    buffers     cached
      Mem:          1843        122       1721          0          9         43
      -/ buffers/cache:         68       1774
      Swap:         3888          0       3888
                   total       used       free     shared    buffers     cached
      Mem:          1843       1744         99          0         26       1614
      -/ buffers/cache:        104       1739
      Swap:         3888          0       3888
      # 重启系统
      reboot
      # 挂载 memcg
      mount -t cgroup -o memory memcg /mnt/cgroup
      # 创建 组A
      mkdir /mnt/cgroup/A
      # 将当前 shell 加入到组A
      echo ¥¥> /mnt/cgroup/A/tasks
      # 限制 组A 的内存使用量最大为 10MB
      echo 10M > /mnt/cgroup/A/memory.limit_in_bytes
      # 测试限制内存为 10MB 时, 内存的使用情况.
      rm -rf linux-source-3.2.tar.gz
      free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                   total       used       free     shared    buffers     cached
      Mem:          1843        122       1721          0         10         43
      -/ buffers/cache:         68       1774
      Swap:         3888          0       3888
                   total       used       free     shared    buffers     cached
      Mem:          1843        194       1649          0         14         48
      -/ buffers/cache:        131       1712
      Swap:         3888          0       3888
      从上面的结果可以看出限制内存是起了作用的.
      不限制内存时, tar 压缩前后 buffer cache 内存从 (9MB 43MB) ==> (26MB 1614MB)  增大了 1588MB
      限制内存后, tar 压缩前后 buffer cache 内存从 (10MB 43MB) ==> (14MB 48MB)  增大了 9MB
       
      总结
      简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.
      cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,
      还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.

    查看评论

    留存 from: and CGroup...

    cgroup的安装

    其实安装很简单,最佳实践就是yum直接安装(centos下)

    IO限制测试

    用dd对硬盘进行写操作

    # dd if=/dev/sda of=/dev/null &

    打开iotop看下IO速度

    Total DISK READ : 100.37M/s | Total DISK WRITE : 0.00 B/s

    Actual DISK READ: 100.37 M/s | Actual DISK WRITE: 0.00 B/s

    TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND

    18081 be/4 root 100.37 M/s 0.00 B/s 0.00 % 1.34 % ddif=/dev/sda of=/dev/null

    为了控制IO速度,在blkio上创建控制组

    # cgcreate -g blkio:/hzmali_test

    查看下硬盘号

    # ls -l /dev/sda

    brw-rw---- 1 root disk 8, 0 Jul 25 22:46 /dev/sda

    设置硬盘号和对应的读取速度限制,然后执行同样的命令

    # cgset -r blkio.throttle.read_bps_device="8:0 1000000" hzmali_test

    # cgexec -g blkio:hzmali_test "dd if=/dev/sda of=/dev/null"

    用iotop查看下,速度果然就降到1M以下

    Total DISK READ : 996.55 K/s | Total DISK WRITE : 0.00 B/s

    Actual DISK READ: 996.55 K/s | Actual DISK WRITE: 0.00 B/s

    TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND

    18188 be/4 root 996.55 K/s0.00 B/s 0.00 % 99.99 % dd if=/dev/sda of=/dev/null

    实例3 - 物理CPU的控制

    上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.

    要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.

    首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y

    cat /boot/config-`uname -r` | grep -i cpusets
    CONFIG_CPUSETS=y
    

    我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......

     

    然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况

    1. 卸载当前的 cgroup
    2. 再次挂载 cgroup 文件系统, 并指定 -o cpuset
    3. 指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
    4. 指定 B 的物理CPU也为 0
    5. 重复 实例1 中的步骤, 观察发生的变化

     

    新葡亰496net 17

    umount /mnt/cgroup
    mount -t cgroup -o cpuset cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 14:39 tasks
    
    # 创建子cgroup A 和 B
    mkdir {A,B}
    cat A/cpuset.cpus   
             <--  默认是空的
    echo 0 > A/cpuset.cpus
    cat A/cpuset.cpus 
    0
    echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0
    # 当前Shell加入到 A组
    echo $$ > /mnt/cgroup/A/tasks 
    -bash: echo: write error: No space left on device
    

    新葡亰496net 18

     

    如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: )

    新葡亰496net 19

    # 同时设置 A 的 cpuset.cpus 和 cpuset.mems
    echo 0 > A/cpuset.cpus
    echo 0 > A/cpuset.mems
    # B组也同样设置
    echo 0 > B/cpuset.cpus
    echo 0 > B/cpuset.mems
    
    # 将当前 shell 加入到 A组
    echo $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
    stress -c 2
    
    # 再打开一个Shell窗口, 并加入到 B组
    echo $$ > /mnt/cgroup/B/tasks
    stress -c 2
    
    # 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
    top
    top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 50.0 us,  0.0 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
    3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
    3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
    3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
    3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
    

    新葡亰496net 20

    从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,

    所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.

     

    如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.

    下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.

    新葡亰496net 21

    # 在 B组的 shell 窗口中执行以下命令
    echo 1 > /mnt/cgroup/B/cpuset.cpus
    cat /mnt/cgroup/B/cpuset.cpus
    1
    stress -c 2
    
    # 在 A组的 shell 窗口中执行以下命令
    stress -c 2
    
    # 在第3个shell窗口中用top命令查看执行结果
    top
    top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
      PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME   COMMAND                                                                                                                      
     3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
     3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
    

    新葡亰496net 22

    果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.

     

    实例4 - cgroup 对使用的内存的控制

    cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory

    # 首先之前挂载的 cpuset 子系统
    umount /mnt/cgroup
    
    # 挂载cgroup 文件系统, 指定 -o memeory
    mount -o memory -t cgroup memcg /mnt/cgroup/
    mount: special device memcg does not exist
    

     

    出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:

    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    0              <-- 这里的 enabled 是 0
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    

     

    为了默认启用memory子系统, 可以设置 grub选项

    vim /etc/default/grub
    # 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
    # 保存后, 更新grub.cfg
    update-grub
    reboot
    

     

    重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了

    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    1
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    
    # 挂载cgroup 的memory子系统
    mount -t cgroup -o memory memcg /mnt/cgroup
    ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
    --w------- 1 root root 0 Aug 28 15:54 memory.force_empty
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
    -rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 15:54 tasks
    

     

    开始实验:

    1. 重启系统 (为了保证内存的干净)
    2. 挂载 memcg
    3. 在挂载的 /mnt/cgroup 中创建 组A
    4. 将当前shell 加入到 组A
    5. 不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
    6. 重复步骤 1 ~ 4
    7. 限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化

     

    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0          9         43
    -/  buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843       1744         99          0         26       1614
    -/  buffers/cache:        104       1739
    Swap:         3888          0       3888
    
    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 限制 组A 的内存使用量最大为 10MB
    echo 10M > /mnt/cgroup/A/memory.limit_in_bytes
    
    # 测试限制内存为 10MB 时, 内存的使用情况.
    rm -rf linux-source-3.2.tar.gz
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0         10         43
    -/  buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843        194       1649          0         14         48
    -/  buffers/cache:        131       1712
    Swap:         3888          0       3888
    

    从上面的结果可以看出限制内存是起了作用的.

    不限制内存时, tar 压缩前后 buffer cache 内存从 (9MB 43MB) ==> (26MB 1614MB)  增大了 1588MB

    限制内存后, tar 压缩前后 buffer cache 内存从 (10MB 43MB) ==> (14MB 48MB)  增大了 9MB

     

    配置文件

    /etc/cgconfig.conf

    mount {          cpuset  = /cgroup/cpuset;          
                          cpu     = /cgroup/cpu;          
                          cpuacct = /cgroup/cpuacct;          
                          memory  = /cgroup/memory;          
                          devices = /cgroup/devices;          
                          freezer = /cgroup/freezer;          
                          net_cls = /cgroup/net_cls;          
                           blkio   = /cgroup/blkio;              
                             }  
    

     

    实例4 - cgroup 对使用的内存的控制

    cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory

    # 首先之前挂载的 cpuset 子系统
    umount /mnt/cgroup
    
    # 挂载cgroup 文件系统, 指定 -o memeory
    mount -o memory -t cgroup memcg /mnt/cgroup/
    mount: special device memcg does not exist
    

     

    出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:

    新葡亰496net 23

    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    0              <-- 这里的 enabled 是 0
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    

    新葡亰496net 24

     

    为了默认启用memory子系统, 可以设置 grub选项

    vim /etc/default/grub
    # 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
    # 保存后, 更新grub.cfg
    update-grub
    reboot
    

     

    重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了

    新葡亰496net 25

    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    1
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    
    # 挂载cgroup 的memory子系统
    mount -t cgroup -o memory memcg /mnt/cgroup
    ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
    --w------- 1 root root 0 Aug 28 15:54 memory.force_empty
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
    -rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 15:54 tasks
    

    新葡亰496net 26

     

    开始实验:

    1. 重启系统 (为了保证内存的干净)
    2. 挂载 memcg
    3. 在挂载的 /mnt/cgroup 中创建 组A
    4. 将当前shell 加入到 组A
    5. 不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
    6. 重复步骤 1 ~ 4
    7. 限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化

     

    新葡亰496net 27

    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0          9         43
    -/  buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843       1744         99          0         26       1614
    -/  buffers/cache:        104       1739
    Swap:         3888          0       3888
    
    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 限制 组A 的内存使用量最大为 10MB
    echo 10M > /mnt/cgroup/A/memory.limit_in_bytes
    
    # 测试限制内存为 10MB 时, 内存的使用情况.
    rm -rf linux-source-3.2.tar.gz
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0         10         43
    -/  buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843        194       1649          0         14         48
    -/  buffers/cache:        131       1712
    Swap:         3888          0       3888
    

    新葡亰496net 28

    从上面的结果可以看出限制内存是起了作用的.

    不限制内存时, tar 压缩前后 buffer cache 内存从 (9MB 43MB) ==> (26MB 1614MB)  增大了 1588MB

    限制内存后, tar 压缩前后 buffer cache 内存从 (10MB 43MB) ==> (14MB 48MB)  增大了 9MB

     

    总结

    简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.

    cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,

    还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.

    cgroup section的语法格式如下

    1. group <name> {  
    2.     [<permissions>]  
    3.     <controller> {  
    4.         <param name> = <param value>;  
    5.         …  
    6.     }  
    7.     …}  

    name: 指定cgroup的名称
    permissions:可选项,指定cgroup对应的挂载点文件系统的权限,root用户拥有所有权限。
    controller:子系统的名称
    param name 和 param value:子系统的属性及其属性值

    总结

    简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.

    cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,

    还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.

    7.1 配置对mysql实例的资源限制

        前提:MySQL数据库已在机器上安装

        7.1.1 修改cgconfig.conf文件

    [plain] view plain copy

    1. mount {  
    2.     cpuset  = /cgroup/cpuset;  
    3.     cpu = /cgroup/cpu;  
    4.     cpuacct = /cgroup/cpuacct;  
    5.     memory  = /cgroup/memory;  
    6.         blkio   = /cgroup/blkio;  
    7. }  
    8.   
    9. group mysql_g1 {    
    10.     cpu {  
    11.             cpu.cfs_quota_us = 50000;  
    12.             cpu.cfs_period_us = 100000;  
    13.     }  
    14.     cpuset {    
    15.             cpuset.cpus = "3";    
    16.             cpuset.mems = "0";    
    17.     }    
    18.     cpuacct{  
    19.   
    20.     }  
    21.     memory {    
    22.             memory.limit_in_bytes=104857600;  
    23.             memory.swappiness=0;  
    24.             # memory.max_usage_in_bytes=104857600;  
    25.             # memory.oom_control=0;  
    26.     }   
    27.     blkio  {  
    28.            blkio.throttle.read_bps_device="8:0 524288";  
    29.            blkio.throttle.write_bps_device="8:0 524288";  
    30.     }   
    31. }   

        7.1.2 配置文件的部分解释。

        cpu:cpu使用时间限额。

        cpu.cfs_period_us和cpu.cfs_quota_us来限制该组中的所有进程在单位时间里可以使用的cpu时间。这里的cfs是完全公平调度器的缩写。cpu.cfs_period_us就是时间周期(微秒),默认为100000,即百毫秒。cpu.cfs_quota_us就是在这期间内可使用的cpu时间(微秒),默认-1,即无限制。(cfs_quota_us是cfs_period_us的两倍即可限定在双核上完全使用)。

        cpuset:cpu绑定

        我们限制该组只能在0一共1个超线程上运行。cpuset.mems是用来设置内存节点的。

        本例限制使用超线程0上的第四个cpu线程。

        其实cgconfig也就是帮你把配置文件中的配置整理到/cgroup/cpuset这个目录里面,比如你需要动态设置mysql_group1/ cpuset.cpus的CPU超线程号,可以采用如下的办法。

    [plain] view plain copy

    1. [root@localhost ~]# echo "0" > mysql_group1/ cpuset.cpus  

        cpuacct:cpu资源报告

        memory:内存限制 

        内存限制我们主要限制了MySQL可以使用的内存最大大小memory.limit_in_bytes=256M。而设置swappiness为0是为了让操作系统不会将MySQL的内存匿名页交换出去。

        blkio:BLOCK IO限额

        blkio.throttle.read_bps_device="8:0 524288"; #每秒读数据上限
        blkio.throttle.write_bps_device="8:0 524288"; #每秒写数据上限

        其中8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看

    [plain] view plain copy

    1. [root@localhost /]# ls -l /dev/sda  
    2. brw-rw----. 1 root disk 8, 0 Sep 15 04:19 /dev/sda  

        7.1.3 拓展知识

        现在较新的服务器CPU都是numa结构<非一致内存访问结构(NUMA:Non-Uniform Memory Access)>,使用numactl --hardware可以看到numa各个节点的CPU超线程号,以及对应的节点号。

        本例结果如下:

    [plain] view plain copy

    1. [root@localhost /]# numactl --hardware   
    2. available: 1 nodes (0)  
    3. node 0 cpus: 0 1 2 3  
    4. node 0 size: 1023 MB  
    5. node 0 free: 68 MB  
    6. node distances:  
    7. node   0   
    8.   0:  10   

        以下是较高端服务器的numa信息,仅作参考。

    [plain] view plain copy

    1. [root@localhost ~]# numactl --hardware     
    2. available: 4 nodes (0-3)  
    3. node 0 cpus: 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60  
    4. node 0 size: 16338 MB  
    5. node 0 free: 391 MB  
    6. node 1 cpus: 1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61  
    7. node 1 size: 16384 MB  
    8. node 1 free: 133 MB  
    9. node 2 cpus: 2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62  
    10. node 2 size: 16384 MB  
    11. node 2 free: 137 MB  
    12. node 3 cpus: 3 7 11 15 19 23 27 31 35 39 43 47 51 55 59 63  
    13. node 3 size: 16384 MB  
    14. node 3 free: 186 MB  
    15. node distances:  
    16. node   0   1   2   3   
    17.   0:  10  20  30  20   
    18.   1:  20  10  20  30   
    19.   2:  30  20  10  20   
    20.   3:  20  30  20  10  

        7.1.4 修改cgrules.conf文件

    [plain] view plain copy

    1. [root@localhost ~]# vi /etc/cgrules.conf  
    2. # /etc/cgrules.conf  
    3. #The format of this file is described in cgrules.conf(5)  
    4. #manual page.  
    5. #  
    6. # Example:  
    7. #<user>         <controllers>   <destination>  
    8. #@student       cpu,memory      usergroup/student/  
    9. #peter          cpu             test1/  
    10. #%              memory          test2/  
    11. *:/usr/local/mysql/bin/mysqld * mysql_g1  

        注:共分为3个部分,分别为需要限制的实例,限制的内容(如cpu,memory),挂载目标。

        7.2 使配置生效

    [plain] view plain copy

    1. [root@localhost ~]# /etc/init.d/cgconfig restart  
    2. Stopping cgconfig service:                                 [  OK  ]  
    3. Starting cgconfig service:                                 [  OK  ]  
    4. [root@localhost ~]# /etc/init.d/cgred restart  
    5. Stopping CGroup Rules Engine Daemon...                     [  OK  ]  
    6. Starting CGroup Rules Engine Daemon:                       [  OK  ]  

        注:重启顺序为cgconfig -> cgred ,更改配置文件后两个服务需要重启,且顺序不能错。

        7.3 启动MySQL,查看MySQL是否处于cgroup的限制中

    [plain] view plain copy

    1. [root@localhost ~]# ps -eo pid,cgroup,cmd | grep -i mysqld  
    2. 29871 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/ /bin/sh ./bin/mysqld_safe --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/  
    3. 30219 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/mysql_g1 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/ --plugin-dir=/usr/local/mysql//lib/plugin --user=mysql --log-error=/usr/local/mysql/data//localhost.localdomain.err --pid-file=/usr/local/mysql/data//localhost.localdomain.pid --socket=/tmp/mysql.sock --port=3306  
    4. 30311 blkio:/;net_cls:/;freezer:/;devices:/;memory:/;cpuacct:/;cpu:/;cpuset:/ grep -i mysqld  

        7.4 资源限制验证

        使用mysqlslap对mysql进行压力测试,看mysql使用资源是否超过限制。

        7.4.1 在shell窗口1用mysqlslap对mysql进行压力测试。

    [plain] view plain copy

    1. [root@localhost /]# /usr/local/mysql/bin/mysqlslap --defaults-file=/etc/my.cnf --concurrency=150 --iterations=1 --number-int-cols=8 --auto-generate-sql --auto-generate-sql-load-type=mixed --engine=innodb --number-of-queries=100000 -ujesse -pjesse --number-char-cols=35 --auto-generate-sql-add-autoincrement --debug-info -P3306 -h127.0.0.1  

        7.4.2 在shell窗口2查看mysql对cpu,内存的使用
    新葡亰496net 29

        可见:cpu限制在了第四个核心上,且对第四个核心的使用限制在50%。

        7.4.3 在shell窗口3查看io的消耗

    新葡亰496net 30

        可见:mysql对io的读及写消耗均限制在2M每秒以内。

    8 cgroup实例分析(手工动态验证)

        还原配置文件/etc/cgconfig.conf及/etc/cgrules.conf 为默认配置。测试实例依然为mysql,测试工具为mysqlslap。

        开启cgconfig及cgrules 服务。

    [plain] view plain copy

    1. [root@localhost /]# /etc/init.d/cgconfig restart  
    2. Stopping cgconfig service:                                 [  OK  ]  
    3. Starting cgconfig service:                                 [  OK  ]  
    4. [root@localhost /]# /etc/init.d/cgred restart  
    5. Stopping CGroup Rules Engine Daemon...                     [  OK  ]  
    6. Starting CGroup Rules Engine Daemon:                       [  OK  ]  

        开启mysqlslap压力测试程序。

    [plain] view plain copy

    1. [root@localhost /]# /usr/local/mysql/bin/mysqlslap --defaults-file=/etc/my.cnf --concurrency=150 --iterations=1 --number-int-cols=8 --auto-generate-sql --auto-generate-sql-load-type=mixed --engine=innodb --number-of-queries=100000 -ujesse -pjesse --number-char-cols=35 --auto-generate-sql-add-autoincrement --debug-info -P3306 -h127.0.0.1  

        通过htop查看资源消耗。

    新葡亰496net 31

        8.1 cpu限制实例

        限制mysql使用一个核,如第2个核,且对该核的使用不超过50%

    [plain] view plain copy

    1. [root@localhost /]# mkdir -p /cgroup/cpu/foo/  
    2. [root@localhost /]# mkdir -p /cgroup/cpuset/foo/  
    3. [root@localhost /]# echo 50000 > /cgroup/cpu/foo/cpu.cfs_quota_us  
    4. [root@localhost /]# echo 100000 > /cgroup/cpu/foo/cpu.cfs_period_us  
    5. [root@localhost /]# echo "0" > /cgroup/cpuset/foo/cpuset.mems  
    6. [root@localhost /]# echo "1" > /cgroup/cpuset/foo/cpuset.cpus  
    7. [root@localhost /]# echo 28819 > /cgroup/cpu/foo/tasks   

        其中:28819为mysqld的进程号。

    新葡亰496net 32

        8.2 内存限制实例

        限制mysql使用内存为不超过512M

        跑一个消耗内存脚本

    [plain] view plain copy

    1. x='a'  
    2. while [ True ];do  
    3.     x=$x$x  
    4. done;  

    新葡亰496net 33

        内存的消耗在不断增加,对其进行限制,使其使用内存在500M以内

    [plain] view plain copy

    1. [root@localhost /]# mkdir -p /cgroup/memory/foo  
    2. [root@localhost /]# echo 524288000 >  /cgroup/memory/foo/memory.limit_in_bytes  
    3. [root@localhost /]# echo 44476 > /cgroup/memory/foo/tasks   

    新葡亰496net 34
        内存使用得到了有效控制。

        8.3 IO限制实例

        跑一个消耗IO的测试

    [plain] view plain copy

    1. [root@localhost ~]# dd if=/dev/sda of=/dev/null   

        通过iotop看io占用情况,磁盘读取速度到了50M/s

    新葡亰496net 35 
        限制读取速度为10M/S

    [plain] view plain copy

    1. [root@localhost ~]# mkdir -p /cgroup/blkio/foo  
    2. [root@localhost ~]# echo '8:0   10485760' >  /cgroup/blkio/foo/blkio.throttle.read_bps_device  
    3. [root@localhost ~]# echo 45033 > /cgroup/blkio/foo/tasks  

        注1:45033为dd的进程号

        注2:8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看

    [plain] view plain copy

    1. [root@localhost ~]# ls -l /dev/sda  
    2. brw-rw----. 1 root disk 8, 0 Sep 15 04:19 /dev/sda  

    9 cgroup小结

        使用cgroup临时对进程进行调整,直接通过命令即可,如果要持久化对进程进行控制,即重启后依然有效,需要写进配置文件/etc/cgconfig.conf及/etc/cgrules.conf 

       

    ****************************************************************************************
        原文地址:
        博客主页:

    来自为知笔记(Wiz)

    本文由新葡亰496net发布于服务器网络,转载请注明出处:新葡亰496net:Cgroup和Namespace在测试中的使用,L

    关键词: