分享

Cgroup相关介绍

pig2 发表于 2013-12-12 18:16:59 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 36215
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及其子groupcpu总使用时间(纳秒),内容为0时,充值cpuacct的数据
cpuacct.stat:该group及其子groupcpu的用户和和内核态的分别使用时间 单位为$USER_HZ
    cpuacct.usage_percpu:该group及其子groupcpu分别使用时间(纳秒)


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的group
2:子group的限制要小于父group
3:-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 172227
8:0 Write 120543
8:0 Sync 261857
8:0 Async 30913
8:0 Total 292770
   
         blkio.throttle.io_service_bytes:记录设备读取总数:
8:0 Read 3339509760
8:0 Write 7702714368
8:0 Sync 4183794688
8:0 Async 6858429440
8: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 该文件可能读出的值有三种,其中两种就是前面已提到的FROZENTHAWED,分别代表进程已挂起和已恢复(正常运行),还有一种可能的值为FREEZING,显示该值表示该cgroup中有些进程现在不能被frozen。当这些不能被frozen的进程从该cgroup中消失的时候,FREEZING会变成FROZEN,或者手动将FROZENTHAWED写入一次。
         freezer.state:(仅对非rootgroup有效)
          FROZEN:挂起进程
      FREEZING:显示该值表示有些进程不能被frozen;当不能被挂起的进程从cgroup消失时,变成FROZEN,或者受到改为FROZEN或THAWED
      THAWED :恢复进程
ns      ns子系统是一个比较特殊的子系统。ns子系统没有自己的控制文件,而且没有属于自己的状态信息。
    ns子系统实际上是提供了一种同命名空间的进程聚类的机制。具有相同命名空间的进程会在相同cgroup中。

net_cls
     net_cls.classid :控制该control的类ID(基于tc)
         格式如下:0xAAAABBBB  A代码主类编号,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的VFS
Cgroup中进程组的层级关系与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 和 group
mount 确定每个子系统的挂载位置
mount {
     cpuset = /cgroup/red;  #多个子系统以冒号隔开,并用行分离
}
等于:
mkdir /cgroup/red
mount -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/test
chown -R root:root  /cgroup/memory/test
chown -R halfss:halfss /cgroup/memory/test/tasks
echo 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=1
while True:
     a=i
  i+=1
     在不做任何限制的情况下,该脚本会无限制的占用内存。
2:测试过程:
    1:$ python test.py
    2:ps aux | grep test
        halfss   14795 64.0  2.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 >> tasks
bash: 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的时候没有同时限制内存
    }
}

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条