pig2 发表于 2013-12-12 18:16:59

Cgroup相关介绍

Cgroup目录
1 Cgroup基础... 1
1.1:Cgroups是什么?... 1
1.2:Cgroups可以做什么?... 2
1.3 Cgroups相关概念... 2
1.4 Cgroups子系统... 2
1.4.1 子系统基本介绍... 2
1.4.2子系统关系... 3
1.4.3子系统相应参数介绍... 3
1.5 Cgroups文件系统... 3
2:cgroup基本管理及应用... 3
2.1 cgroup的管理... 3
2.2cgroup的测试... 3
3:结语... 3
4:常见问题... 3

1 Cgroup基础

1.1:Cgroups是什么?Cgroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。最初由google的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有cgroups就没有LXC。 我们可以对 Cgroups 进行监控,禁止 Cgroups 控制下的进程访问某些资源,还可以在一个运行中的系统中对 Cgroups 动态地进行配置。cgconfig ( control group config ) 是一项系统服务,它可以根据配置文件创建 Cgroups,我们可以通过它在每次重启操作系统之后保持一致的 Cgroups 配置。

1.2:Cgroups可以做什么?Cgroups最初的目标是为资源管理提供的一个统一的框架,既整合现有的cpuset等子系统,也为未来开发新的子系统提供接口。现在的cgroups适用于多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化(OS Level Virtualization)。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子系统可以将进程组挂起和恢复。
1.3 Cgroups相关概念

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

1.4 Cgroups子系统


1.4.1 子系统基本介绍


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

1: 系统中第一个被创建的cgroup被称为root cgroup,该cgroup的成员包含系统中所有的进程
2:一个层级中不能出现重复的子系统。
3:进程与Cgroup属于多对多的关系。
4:一个进程创建了子进程后,该子进程默认为父进程所在cgroup的成员。
5:一个任务不能同时属于同一个层次结构中的两个 cgroup。

1.4.3子系统相应参数介绍

通用项目:
          tasks 属于该group的进程ID
   cgroup.procs 属于该group的线程ID   cgroup.event_control 属于cgroup的通知API,允许改变cgroup的状态   notify_on_release 布尔值 是否启用客户端通知,启用时,内核执行release_agent时,cgroup不在包含任何任务(去清空tasks内容)。提供了一个清空group的方法。          注意:root的group默认是0,非root的group和其父group一样     release_agent:仅适用于root group;当notify on release被触发时,执行该文件命令;当一个gorup进程全部清空,并且启用了notify_on_release。
cpu    


cpu子系统用于控制cgroup中所有进程可以使用的cpu时间片。附加了cpu子系统的hierarchy下面建立的cgroup的目录下都有一个cpu.shares的文件,对其写入整数值可以控制该cgroup获得的时间片。例如:在两个 cgroup 中都将 cpu.shares 设定为 1 的任务将有相同的 CPU 时间,但在 cgroup 中将 cpu.shares 设定为 2 的任务可使用的 CPU 时间是在 cgroup 中将 cpu.shares 设定为 1 的任务可使用的 CPU 时间的两倍。
   cpu子系统是通过Linux CFS调度器实现的。按照作者Ingo Molnar的说法:"CFS百分之八十的工作可以用一句话概括:CFS在真实的硬件上模拟了完全理想的多任务处理器"。

cpu子系统调度CPU的访问控制,这里有2种调度模式
CFS(Completely Fair Scheduler):


基于linux的CFS及各group的cpu的权重,在croup的task间分配CPU
   在CFS中,如果CPU空闲较多,那么group的task可能可以获得额外的CPU资源
   cpu.cfs_period_us:该group的cpu分配周期(微妙),如果想让该group在1s内能又0.5秒的cpu使用时间设置cpu.cfs_period_us为1000000,设置cpu.cfs_quota_us为500000;如果想让该group使用2个CPU,设置cpu.cfs_quota_us
为2000000,设置cpu.cfs_period_us为1000000
   cpu.cfs_quota_us:该指为-1时表示不限制CPU使用
   cpu.stat:统计CPU的使用状态
               nr_periods:CPU的使用周期(有多少个cpu.cfs_period_us)
               nr_throttled :超出CPU限制的次数
               throttled_time:被KILL的任务的cpu使用时间
   cpu.shares:一个整数值(大于等于2),指定了使用CPU的权重(相对于系统上的
            所有CPU),2048的group可使用的cpu资源位1024的2倍。
如果当前group的有闲置的cpu资源,那么这些资源可以被分配给其他的group使用

RTS(Real-Time scheduler):直接通过tasks的cpu使用时间来调度CPU
   cpu.rt_period_us:(仅适用于实时任务调度)该参数指定了一段时间内风给该group的CPU使用时间(微秒)。如果该值设置为200000,cpu.rt_period_us设置为1000000,那么每秒该group有0.2秒的cpu使用时间
   cpu.rt_runtime_us:(仅适用于实时任务调度)指定了该group可以持续使用CPU的最长时间。如果想让该group在1秒内有0.2秒的cpu使用时间,设置cpu.rt_runtime_us为200000,设置cpu.rt_period_us为1000000;如果想让该group有2个cpu的资源设置改制为2000000,设置cpu.rt_period_us为1000000。

cpuacct     cpuacct.usage:该group及其子group的cpu总使用时间(纳秒),内容为0时,充值cpuacct的数据 cpuacct.stat:该group及其子group的cpu的用户和和内核态的分别使用时间 单位为$USER_HZ     cpuacct.usage_percpu:该group及其子group的cpu分别使用时间(纳秒)

cpuset         cpuset.cpus:绑定该group的cpu节点,如绑定该进程可以使用4,5,6,17,18 5
个cpu,格式如下:
         4-6,17,18     cpu.mems:绑定该group的内存节点,格式如上    cpuset.memory_migrate:布尔值,默认0,指定当内存节点变化是,原内存页面是否迁移到新的内存节点上。     cpuset.cpu_exclusive:布尔值,默认0,指定该group的子group是否可以共享该group的cpu     cpuset.mem_exclusive:布尔值,默认0,指定该group的子group是否可以共享该group的内存     cpuset.mem_hardwall:布尔值,默认0,内核为该group分配的进程是否应该仅仅在指定的内存节点上。     cpuset.memory_pressure:统计了该group内存压力的平均值(仅在cpuset.memory_pressure_enabled启用是有效)             该值为:每秒该group试图尝试回收内存的次数*1000     cpuset.memory_pressure_enabled:布尔值,默认0     cpuset.memory_spread_page:布尔值,默认0,是否均衡使用该group的内存节点     cpuset.memory_spread_slab:布尔值,默认0,是否均衡使用该group的cpu节点     cpuset.sched_load_balance:布尔值,默认1,是否平均分配该group的cpu负载到该group的节点上,注意,如果父group启用了这项,那么当前项就不在有效。     cpuset.sched_relax_domain_level:一个-1至5;代表系统试图进行负载均衡的类型(仅在 cpuset.sched_load_balance启用时有效)l         -1:使用系统默认值l         0:定期负载均衡l         1:实时在同一内核线程间进行负载均衡l         2:实时在同一内核包间负载均衡l         3:实时在同一cpu节点或者刀片上负载均衡l         4:实时在多个CPU(NUMA)节点负载均衡l         5:实时在所有cpu间负载均衡
memory
memory 子系统可以设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。memory子系统是通过linux的resource counter机制实现的。
memory.stat:统计内存使用状态   memory.usage_in_bytes:当前cgroup的内存使用情况
memory.memsw.usage_in_bytes:当前group的内存+swap的内存使用情况
memory.limit_in_bytes:设定最大的内存使用量,可以加单位(k/K,m/M,g/G)       注意:1:不能现在root的group2:子group的限制要小于父group3:-1是不限制 memory.memsw.limit_in_bytes:设定内存和swap总和的最大使用量,其他同上        注意:设置memory.memsw.limit_in_bytes前要设置memory.limit_in_bytes   memory.failcnt:统计达到内存限制(memory.limit_in_bytes)的次数 memory.memsw.failcnt:统计达到内存+swap限制(memory.memsw.limit_in_bytes)的次数 memory.force_empty:当设置为0时,情况该group的所有内存页;该选项只有在当前group没有tasks才可以使用 memory.swappiness:针对该group的交换分区的优先级,类似vm.swappiness      注意:1: 不能调整root的group的swappiness             2: 不能调整有子group的swappiness   memory.use_hierarchy:布尔值,默认0;指定是否在整个group层限制内存 memory.oom_control:布尔值;默认0;指定是否杀掉超出内存使用限制的进程。0:kill哪些超出内存使用范围的进程,1:暂停哪些超出内存使用范围的进程,指定有多余的内存。       该项也指出了是否有进程因为内存使用过多被暂停,under_oom为1 blkio     该子系统提供了2中方式来控制IO     1:基于权重          每个group都可以设置一个数值,根据数值的不通,系统分配相应的IO          blkio.weight:一个100-1000的数值             echo 1000 > blkio.weight           blkio.weight_device:一个100-1000的数值,指定设备的IO权重             echo "8:0 500" > blkio.weight_device          以上2个值同一个group只能存在一个 附:linux设备编号详情见:https://www.kernel.org/doc/Documentation/devices.txt             8 block SCSI disk devices (0-15)                   0 = /dev/sda          First SCSI disk whole disk               16 = /dev/sdb          Second SCSI disk whole disk               32 = /dev/sdc          Third SCSI disk whole disk                  ...                240 = /dev/sdp          Sixteenth SCSI disk whole disk                 Partitions are handled in the same way as for IDE                disks (see major number 3) except that the limit on                partitions is 15.              2:基于速度:          每个group都有一个最大的速度,该group的进程IO不能大于这个速度          主要控制项:        blkio.throttle.read_bps_device:指定该设备上的最大读速度(bytes/s)             echo "8:0 10485760" > blkio.throttle.read_bps_device          blkio.throttle.read_iops_device:制定该设备上的最大读IO(IO read/s)             echo "8:0 10" > blkio.throottle.read_iops_device          下面2个跟上面2个类似          blkio.throttle.write_bps_device            blkio.throttle.write_iops_device          主要记录项:          blkio.throttle.io_serviced:记录设备IO操作总数:8:0 Read 1722278:0 Write 1205438:0 Sync 2618578:0 Async 309138:0 Total 292770              blkio.throttle.io_service_bytes:记录设备读取总数:8:0 Read 33395097608:0 Write 77027143688:0 Sync 41837946888:0 Async 68584294408:0 Total 11042224128           其他配置项:           blkio.reset_stats:对当前文件写入一个整数可重置当前所有数据           blkio.time:指定设备的cgroup控制的IO访问时间(ms)           blkio.sectors:指定设备的扇区操作数           blkio.io_service_time:制定设备的IO工作时间(ns)           blkio.io_wait_time:Cgroup等待IO的时间           blkio.io_merged:被合并的IO请求           blkio.io_queued:被cgroup放到队列的IO请求          注意如果不启用增强版的IO隔离,cgroup的IO隔离仅仅对顺序IO有效,启用后对逻辑IO也有效,默认启用        echo 1 > /sys/block/<disk_device>/queue/iosched/group_isolatio    devices devices子系统是通过提供device whilelist 来实现的,devices子系统通过在内核对设备访问的时候加入额外的检查来实现;而devices子系统本身只需要管理好可以访问的设备列表就行了。    devices.allow:指定该group各设备的访问权限,有4个字段          type:             a:所有设备             b:块设备             c:字符型          major,minor:主副设备号          access:             r:读             w:写             m:创建新设备     devices.allow:指定该group各设备的不可访问权限,语法同上     devices.list:统计该group所有权限 freezer 该文件可能读出的值有三种,其中两种就是前面已提到的FROZEN和THAWED,分别代表进程已挂起和已恢复(正常运行),还有一种可能的值为FREEZING,显示该值表示该cgroup中有些进程现在不能被frozen。当这些不能被frozen的进程从该cgroup中消失的时候,FREEZING会变成FROZEN,或者手动将FROZEN或THAWED写入一次。
         freezer.state:(仅对非root的group有效)
          FROZEN:挂起进程       FREEZING:显示该值表示有些进程不能被frozen;当不能被挂起的进程从cgroup消失时,变成FROZEN,或者受到改为FROZEN或THAWED       THAWED :恢复进程ns    ns子系统是一个比较特殊的子系统。ns子系统没有自己的控制文件,而且没有属于自己的状态信息。
    ns子系统实际上是提供了一种同命名空间的进程聚类的机制。具有相同命名空间的进程会在相同cgroup中。

net_cls   net_cls.classid :控制该control的类ID(基于tc)          格式如下:0xAAAABBBBA代码主类编号,B代码副类编号,如果没有就写0,并且0是可以省略的          0x10001=0x0000100001=0x1:1 net_prio   net_prio.prioidx:只读文件,包含内核中用来表示该group的唯一整数值   net_prio.ifpriomap:指定各个网卡的该group的优先级格式: eth0 2          注意,1:子group默认使用父group的优先级               :2:值越大优先级越低
1.5 Cgroups文件系统


Cgroup提供了一个伪文件系统来对上面的各个子系统及参数进行管理
Cgroups用户空间的管理是通过cgroup文件系统实现的。当创建一个cgroup实例时至少指定一种子系统,这样新建的进程组在访问子系统对应的子资源时,就有了相应的限制。Cgroup的文件系统实现类似linux的VFSCgroup中进程组的层级关系与linux中进程的层级关系类似,在linux中一个进程通过fork()调用创建了一个子进程,这2个进程间存在父子的关系,并且子进程可以继承父进程的一些资源,系统中的进程形成一个树形的等级关系,每个进程的位置也都是唯一的。对于Cgroup来说,cgroup实例间也是有具体级别关系的,子group会继承父group对资源的控制属性,该层级关系是为了更细粒度的进程资源控制
比如创建一个层级:
mount -t cgroup -o cpu,cpuset,memory cpu_and_mem /cgroup/cpu_and_mem
创建一个cgroup:
cd /cgroup/cpu_and_mem
mkdir foo
通过以上两个命令,我们就在刚才创建的层级下创建了一个叫foo的cgroup。
你再cd foo,然后ls,直接就能看到刚刚创建的文件夹下就已经有了一些东西

2:cgroup基本管理及应用
2.1 cgroup的管理


redhat通过了一个管理套件:libcgroup

安装:yum install libcgroup 该管理套件提供了一个服务:cgconfig,配置文件为:/etc/cgconfig.conf改配置文件主要分为2快:mount 和 groupmount 确定每个子系统的挂载位置mount {   cpuset = /cgroup/red;#多个子系统以冒号隔开,并用行分离}等于:mkdir /cgroup/redmount -t cgroup -o cpuset red /cgroup/red group 管理cgroup实体和相应子系统的参数风格如下:group <name> {     perm {#权限这块是可选的          task {             uid = <task user>,             gid = <task gropu>,          }          admin {             uid = root,             gid = root,          }   }     <controller>{          <param name> = <param value>,          ....   }     ....} 示例: group test {
    perm {        admin { #指定了那个用户可以调整限制的参数
          uid = root;
            gid = root;
      }       task {#指定了那个用户可以调整限制的进程,只需将进程号输入到tasks文件中即可
          uid = halfss;
            gid = halfss;
      }
    }
    memory {
      memory.limit_in_bytes = 53687091;
    }
} 这样的配置相当于执行了如下一些命令:mkdir /cgroup/memory/testchown -R root:root/cgroup/memory/testchown -R halfss:halfss /cgroup/memory/test/tasksecho 53687091 > /cgroup/memory/test/memory.limit_in_bytes 注意:1:该配置文件需要cgconfig服务重启后生效2:重启的时候不能有用户停留在cgroup的子系统中 上述的这些功能,mount和group的管理,即可以通过刚才的配置文件也可以通过命令行。无论是配置文件还是命令行对cgroup的管理最终都是修改的cgroup的文件系统,而该文件系统是无状态的;也就意味着通过命令调整完毕后(可以通过命令生成配置文件当做快照),重启后你做的工作都没了,所以这里推荐用配置文件进行管理。这里说下基本的命令:1:cgroup文件系统的挂载mount -t cgroup -o subsystem1,sub system2 name /mount_point #mkdir /cgroup/cpu_and_mem#mount -t cgroup -o cpu,cpuset,memory cpuu_and_memory /cgroup/cpu_and_mem# lssubsys-am
ns
cpuacct
devices
freezer
net_cls
blkio
perf_event
net_prio
cpuset,cpu,memory /cgroup/cpu_and_mem# umount/cgroup/cpu_and_mem
# lssubsys返回空了 2.2cgroup的测试测试:1:测试代码#!/usr/bin/env python#coding=utf8 a={}i=1while True:   a=ii+=1    在不做任何限制的情况下,该脚本会无限制的占用内存。 2:测试过程:     1:$ python test.py     2:ps aux | grep test      halfss   14795 64.02.0 277156 165924 pts/0   R+   02:32   0:01 python test.py
      echo 14795 >> /cgroup/memory/test/tasks   3:$ python test.py
      Killed#这里可以看得过一会后,该进程被kill掉了,其实可以让他暂停,具体操作参加上文 3:结语了解了cgroup的基本架构,工作原理及使用方法后,剩下的就是灵活的使用cgroup来为我们服务了 4:常见问题: 问题1:echo 3 >> tasks
-bash: echo: write error: Invalid argument原因:不能将内核进程放到cgroup里,也是内核自己限制不了自己 问题3:echo 4 >> tasksbash: echo:write error:No space left on device 原因:group os {
    memory {
      memory.limit_in_bytes = 1G;
    }
    cpuset {
      cpuset.cpus = 0;
      cpuset.mems = 0;在cpuset中限制cpu的时候没有同时限制内存
    }
}
页: [1]
查看完整版本: Cgroup相关介绍