1、Cgroup安装

安装Cgroups需要libcap-devel和libcgroup两个相关的包

yum install gcc libcap-devel

2、Cgroup挂载配置

Cgroup对应服务名称为cgconfig,cgconfig默认采用“多挂载点”挂载。经过实际测试,发现在CentOS环境中应采用“单挂载点”进行挂载,因此应当卸载原有cgroup文件系统,并禁用cgconfig。
cgclear或者sudo service cgconfig stop # 停止cgconfig,卸载cgroup目录
sudo chkconfig cgconfig off # 禁用cgconfig服务,避免其开机启动
然后采用“单挂载点”方式重新挂载cgroup。
可以直接手动挂载,这样仅当次挂载成功。
mount -t cgroup none /cgroup
然后编辑/etc/fstab/,输入下列内容。这样每次开机后都会自动挂载。
none /cgroup cgroup defaults 0 0

3、常用的Cgroup相关命令和配置文件

service cgconfig status|start|stop|restart    #查看已存在子系统
lssubsys –am #查看已存在子系统
cgclear # 清除所有挂载点内部文件,相当于service cgconfig stop
cgconfigparser -l /etc/cgconfig.conf #重新挂载 Cgroup默认挂载点(CentOS):/cgroup
cgconfig配置文件:/etc/cgconfig.conf

4、libcgroup Man Page简介

man 1 cgclassify -- cgclassify命令是用来将运行的任务移动到一个或者多个cgroup。
man 1 cgclear -- cgclear 命令是用来删除层级中的所有cgroup。
man 5 cgconfig.conf -- 在cgconfig.conf文件中定义cgroup。
man 8 cgconfigparser -- cgconfigparser命令解析cgconfig.conf文件和并挂载层级。 man 1 cgcreate -- cgcreate在层级中创建新cgroup。
man 1 cgdelete -- cgdelete命令删除指定的cgroup。
man 1 cgexec -- cgexec命令在指定的cgroup中运行任务。
man 1 cgget -- cgget命令显示cgroup参数。
man 5 cgred.conf -- cgred.conf是cgred服务的配置文件。
man 5 cgrules.conf -- cgrules.conf 包含用来决定何时任务术语某些 cgroup的规则。 man 8 cgrulesengd -- cgrulesengd 在 cgroup 中发布任务。
man 1 cgset -- cgset 命令为 cgroup 设定参数。
man 1 lscgroup -- lscgroup 命令列出层级中的 cgroup。
man 1 lssubsys -- lssubsys 命令列出包含指定子系统的层级。

测试一:限制cpu的资源

测试后验证了可以做到:

  • 限制进程的cpu占用百分比
  • 限制多个进程组的之间的cpu使用权重
  • 指定进程的使用的cpu和内存组(绑定cpu)

跑一个耗cpu的脚本

x=0
while [ True ];do
x=$x+1
done;

top可以看到这个脚本基本占了100%的cpu资源

top - 15:30:01 up  1:03,  5 users,  load average: 0.30, 0.50, 0.39
Tasks: 210 total, 2 running, 208 sleeping, 0 stopped, 0 zombie
Cpu(s): 6.3%us, 0.1%sy, 0.0%ni, 93.5%id, 0.2%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 49461228k total, 13412644k used, 36048584k free, 75384k buffers
Swap: 2097148k total, 0k used, 2097148k free, 12498636k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11605 root 20 0 104m 1528 1016 R 99.7 0.0 2:30.48 sh
105 root 20 0 0 0 0 S 0.3 0.0 0:00.11 kworker/8:1

创建一个控制组控制这个进程的cpu资源

mkdir -p /cgroup/cpu/foo	     #新建一个控制组foo
echo 50000 > /cgroup/cpu/foo/cpu.cfs_quota_us #将cpu.cfs_quota_us设为50000,相对于cpu.cfs_period_us的100000是50%
echo 11605 > /cgroup/cpu/foo/tasks

然后top的实时统计数据如下,cpu占用率将近50%,看来cgroups关于cpu的控制起了效果

top - 15:32:48 up  1:06,  5 users,  load average: 0.80, 0.68, 0.48
Tasks: 210 total, 2 running, 208 sleeping, 0 stopped, 0 zombie
Cpu(s): 3.2%us, 0.0%sy, 0.0%ni, 96.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 49461228k total, 13412276k used, 36048952k free, 75400k buffers
Swap: 2097148k total, 0k used, 2097148k free, 12498652k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11605 root 20 0 104m 1724 1016 R 50.2 0.0 5:09.97 sh
11639 root 20 0 15200 1200 820 R 0.3 0.0 0:00.03 top

可以看到,进程的 cpu 占用已经被成功地限制到了 50% 。这里,测试的虚拟机只有一个核心。在多核情况下,看到的值会不一样。另外,cfs_quota_us 也是可以大于 cfs_period_us 的,这主要是对于多核情况。有 n 个核时,一个控制组中的进程自然最多就能用到 n 倍的 cpu 时间。

这两个值在 cgroups 层次中是有限制的,下层的资源不能超过上层。具体的说,就是下层的 cpu.cfs_period_us 值不能小于上层的值,cpu.cfs_quota_us 值不能大于上层的值。

另外的一组 cpu.rt_period_us、cpu.rt_runtime_us 对应的是实时进程的限制,平时可能不会有机会用到。

在 cpu 子系统中,cpu.stat 就是用前面那种方法做的资源限制的统计了。nr_periods、nr_throttled 就是总共经过的周期,和其中受限制的周期。throttled_time 就是总共被控制组掐掉的 cpu 使用时间。

还有个 cpu.shares, 它也是用来限制 cpu 使用的。但是与 cpu.cfs_quota_us、cpu.cfs_period_us 有挺大区别。cpu.shares 不是限制进程能使用的绝对的 cpu 时间,而是控制各个组之间的配额。比如

/cpu/cpu.shares : 1024
/cpu/foo/cpu.shares : 2048

那么当两个组中的进程都满负荷运行时,/foo 中的进程所能占用的 cpu 就是 / 中的进程的两倍。如果再建一个 /foo/bar 的 cpu.shares 也是 1024,且也有满负荷运行的进程,那 /、/foo、/foo/bar 的 cpu 占用比就是 1:2:1 。前面说的是各自都跑满的情况。如果其他控制组中的进程闲着,那某一个组的进程完全可以用满全部 cpu。可见通常情况下,这种方式在保证公平的情况下能更充分利用资源。

此外,还可以限定进程可以使用哪些 cpu 核心。cpuset 子系统就是处理进程可以使用的 cpu 核心和内存节点,以及其他一些相关配置。这部分的很多配置都和 NUMA 有关。其中 cpuset.cpus、cpuset.mems 就是用来限制进程可以使用的 cpu 核心和内存节点的。这两个参数中 cpu 核心、内存节点都用 id 表示,之间用 “,” 分隔。比如 0,1,2 。也可以用 “-” 表示范围,如 0-3 。两者可以结合起来用。如“0-2,6,7”。在添加进程前,cpuset.cpus、cpuset.mems 必须同时设置,而且必须是兼容的,否则会出错。例如

# echo 0 >/sys/fs/cgroup/cpuset/foo/cpuset.cpus
# echo 0 >/sys/fs/cgroup/cpuset/foo/cpuset.mems
这样, /foo 中的进程只能使用 cpu0 和内存节点0。用 # cat /proc/<pid>/status|grep '_allowed_list'

cgroups 除了用来限制资源使用外,还有资源统计的功能。做云计算的计费就可以用到它。有一个 cpuacct 子系统专门用来做 cpu 资源统计。cpuacct.stat 统计了该控制组中进程用户态和内核态的 cpu 使用量,单位是 USER_HZ,也就是 jiffies、cpu 滴答数。每秒的滴答数可以用 getconf CLK_TCK 来获取,通常是 100。将看到的值除以这个值就可以换算成秒。

测试二:限制进程的内存资源

测试后验证了:

  • 限制了资源的占用,达到内存以后,进程直接杀掉

测试方法:

跑一个耗内存的脚本,内存不断增长

x="a"
while [ True ];do
x=$x$x
done;

top看内存占用稳步上升

    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
30215 root 20 0 871m 501m 1036 R 99.8 26.7 0:38.69 sh
30215 root 20 0 1639m 721m 1036 R 98.7 38.4 1:03.99 sh
30215 root 20 0 1639m 929m 1036 R 98.6 49.5 1:13.73 sh

下面用cgroups控制这个进程的内存资源

mkdir -p /cgroup/memory/foo
echo 1048576 > /cgroup/memory/foo/memory.limit_in_bytes #分配1MB的内存给这个控制组
echo 30215 > /cgroup/memory/foo/tasks

发现之前的脚本被kill掉

[root@localhost ~]# sh /home/test.sh
已杀死

因为这是强硬的限制内存,当进程试图占用的内存超过了cgroups的限制,会触发out of memory,导致进程被kill掉。

实际情况中对进程的内存使用会有一个预估,然后会给这个进程的限制超配50%比如,除非发生内存泄露等异常情况,才会因为cgroups的限制被kill掉。

也可以通过配置关掉cgroups oom kill进程,通过memory.oom_control来实现(oom_kill_disable 1),但是尽管进程不会被直接杀死,但进程也进入了休眠状态,无法继续执行,仍然无法服务。

关于内存的控制,还有以下配置文件,关于虚拟内存的控制,以及权值比重式的内存控制等

[root@localhost /]# ls /cgroup/memory/foo/
cgroup.event_control memory.force_empty memory.memsw.failcnt
memory.memsw.usage_in_bytes memory.soft_limit_in_bytes memory.usage_in_bytes tasks
cgroup.procs memory.limit_in_bytes memory.memsw.limit_in_bytes
memory.move_charge_at_immigrate memory.stat memory.use_hierarchy
memory.failcnt memory.max_usage_in_bytes memory.memsw.max_usage_in_bytes
memory.oom_control memory.swappiness notify_on_release

测试三:限制进程的IO资源

测试验证了:

  • 能够控制io设备的读写速度

跑一个耗io的脚本

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

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

30252 be/4 root      284.71 M/s    0.00 B/s  0.00 %  0.00 % dd if=/dev/sda of=/dev/null

下面用cgroups控制这个进程的io资源

mkdir -p /cgroup/blkio/foo

echo '8:0   1048576' >  /cgroup/blkio/foo/blkio.throttle.read_bps_device
#8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看
echo 30252 > /cgroup/blkio/foo/tasks

再通过iotop看,确实将读速度降到了1M/s

30252 be/4 root      993.36 K/s    0.00 B/s  0.00 %  0.00 % dd if=/dev/sda of=/dev/null

对于io还有很多其他可以控制层面和方式,如下

[root@localhost ~]# ls /cgroup/blkio/foo/
blkio.io_merged blkio.io_serviced blkio.reset_stats
blkio.throttle.io_serviced blkio.throttle.write_bps_device blkio.weight cgroup.procs
blkio.io_queued blkio.io_service_time blkio.sectors
blkio.throttle.read_bps_device blkio.throttle.write_iops_device blkio.weight_device notify_on_release
blkio.io_service_bytes blkio.io_wait_time blkio.throttle.io_service_bytes
blkio.throttle.read_iops_device blkio.time cgroup.event_control tasks

blkio 子系统里东西很多。不过大部分都是只读的状态报告,可写的参数就只有下面这几个:

blkio.throttle.read_bps_device
blkio.throttle.read_iops_device
blkio.throttle.write_bps_device
blkio.throttle.write_iops_device
blkio.weight
blkio.weight_device 这些都是用来控制进程的磁盘 io 的。很明显地分成两类,其中带“throttle”的,顾名思义就是节流阀,将流量限制在某个值下。而“weight”就是分配 io 的权重。
再看看 blkio.weight 。blkio 的 throttle 和 weight 方式和 cpu 子系统的 quota 和 shares 有点像,都是一种是绝对限制,另一种是相对限制,并且在不繁忙的时候可以充分利用资源,权重值的范围在 10 – 1000 之间。

测试权重方式要麻烦一点。因为不是绝对限制,所以会受到文件系统缓存的影响。如在虚拟机中测试,要关闭虚机如我用的 VirtualBox 在宿主机上的缓存。如要测试读 io 的效果,先生成两个几个 G 的大文件 /tmp/file_1,/tmp/file_2 ,可以用 dd 搞。然后设置两个权重

# echo 500 >/sys/fs/cgroup/blkio/foo/blkio.weight
# echo 100 >/sys/fs/cgroup/blkio/bar/blkio.weight

测试前清空文件系统缓存,以免干扰测试结果

sync
echo 3 >/proc/sys/vm/drop_caches

在这两个控制组中用 dd 产生 io 测试效果。

# cgexec -g "blkio:foo" dd if=/tmp/file_1 of=/dev/null &
[1] 1838
# cgexec -g "blkio:bar" dd if=/tmp/file_2 of=/dev/null &
[2] 1839

还是用 iotop 看看效果

TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
1839 be/4 root 48.14 M/s 0.00 B/s 0.00 % 99.21 % dd if=/tmp/file_2 of=/dev/null
1838 be/4 root 223.59 M/s 0.00 B/s 0.00 % 16.44 % dd if=/tmp/file_1 of=/dev/null

两个进程每秒读的字节数虽然会不断变动,但是大致趋势还是维持在 1:5 左右,和设定的 weight 比例一致。blkio.weight_device 是分设备的。写入时,前面再加上设备号即可。

实践记录

1、假如已经配置好一个资源组,现在想让一个服务按这个组的资源分配来运行服务,而不需要去找到进程号再写入到tasks中

[root@lab8105 ~]# cgexec -g cpu:daemons/ftp top

这个运行以后有会自动将top进程号写入到tasks当中去

2、查询一个组里面设置的资源的限制

设置的值会显示出来,没有设置的就会提示没有找到

[root@lab8105 ~]# cgget  daemons/ftp
daemons/ftp:
cgget: cannot find controller 'cpuset' in group 'daemons/ftp'
cpu.rt_period_us: 1000000
cpu.rt_runtime_us: 0
cpu.stat: nr_periods 0
nr_throttled 0
throttled_time 0
cpu.cfs_period_us: 5000
cpu.cfs_quota_us: -1
cpu.shares: 1000
cgget: cannot find controller 'cpuacct' in group 'daemons/ftp'
cgget: cannot find controller 'memory' in group 'daemons/ftp'
cgget: cannot find controller 'devices' in group 'daemons/ftp'
cgget: cannot find controller 'freezer' in group 'daemons/ftp'
cgget: cannot find controller 'net_cls' in group 'daemons/ftp'
cgget: cannot find controller 'blkio' in group 'daemons/ftp'

3、需要用两个限制条件对进程进行限制

[root@lab8105 ~]# cgexec -g cpu:daemons/ftp -g memory:daemons/ftp top

4、默认情况下是一个大根,然后分了几个资源系统,还支持做一个子系统组,即单独组建一个资源组,然后对这个资源组里面进行配置,具体方法如下:

mount {
cpu = /cgroup/cpu_and_mem;
memory = /cgroup/cpu_and_mem;
} group daemons/ftp {
cpu {
cpu.shares = "1000";
cpu.cfs_period_us = "5000";
}
memory {
memory.swappiness = "20";
}
}

5、需要创建控制组群,如上的daemons/ftp,想通过命令行的方式创建

[root@lab8105 ~]# cgcreate -g cpu:/zp -g memory:/zp
如上命令使用后会在/cgroup/cpu/中多了zp目录,并且里面是继承的上级的cpu里面的参数,这样就创建了一个zp的组群 删除组群的方式如下(删除cgroup时,其所有任务都移动到了父组群当中):
[root@lab8105 ~]# cgdelete cpu:/zp memory:/zp

6、设置里面的配置参数

需要设置
/cgroup/cpu/daemons/ftp/cpu.shares
执行
[root@lab8105 ~]# cgset -r cpu.shares=500 daemons/ftp
daemons/ftp路径是相对于根的,如果想设置根的这个参数那么就执行
[root@lab8105 ~]# gset -r cpuacct.usage=0 /
这里需要注意,只有某些参数是可以修改的,某些参数是不能修改的
也可以直接echo的方式进行参数的设置

7,移动某个进程到控制组群当中(动态的进行资源的调配)

移动指定进程到指定的控制组当中,创建两个资源组,使用上面的cpu的脚本,然后运行后,使用top进行监控
group half {
cpu {
cpu.cfs_period_us="100000";
cpu.cfs_quota_us="50000";
}
memory {
memory.swappiness = "50";
}
} group eighty {
cpu {
cpu.cfs_period_us = "100000";
cpu.cfs_quota_us="50000";
}
memory {
memory.swappiness = "80";
}
}
[root@lab8105 ~]# cgclassify -g cpu:half 14245
top监控看到cpu的占用为50%
[root@lab8105 ~]# cgclassify -g cpu:eighty 14245
top监控看到cpu的占用为80%
注意支持多进程,多资源组同时移动
[root@lab8105 ~]# cgclassify -g cpu,memory:eighty 14245 14565
备用方法就是直接echo

8、通过规则对指定的进程进行控制

我们还可以通过设置规则来让 cgred(cgroup 规则引擎后台程序)自动将进程分配给特定组。cgred 后台程序根据 /etc/cgrules.conf 文件中的设置将任务移到 cgroup 中

[root@lab8105 ~]# vim /etc/cgrules.conf
[root@lab8105 ~]# man 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/
# End of file
#
root:cpu.sh cpu half/
root cpu half/ 启动监控进程服务
[root@lab8105 ~]# /etc/init.d/cgred

效果如下,运行相同的命令,所占用的cpu的资源按指定的比例进行占用

[root@lab8105 ~]# top
top - 16:00:40 up 1 day, 1:34, 5 users, load average: 1.57, 1.13, 0.90
Tasks: 216 total, 3 running, 213 sleeping, 0 stopped, 0 zombie
Cpu(s): 6.9%us, 0.0%sy, 0.0%ni, 93.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 49461228k total, 49346312k used, 114916k free, 47374260k buffers
Swap: 2097148k total, 0k used, 2097148k free, 33116k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14648 root 20 0 104m 1716 1012 R 99.7 0.0 4:58.38 cpu1.sh
14565 root 20 0 104m 1704 1012 R 10.0 0.0 4:30.53 cpu.sh

如上所述,指定用户,可以指定进程进行控制,也可以指定用户的所有进程进行控制,后台的做的操作就是把进行的号移动到了指定的资源组的task当中去了

cgroup实践-资源控制的更多相关文章

  1. Linux资源控制-CPU和内存

    主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法. CPU资源控制 每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的. Linux系统中有多 ...

  2. Linux资源控制-CPU和内存【转】

    转自:http://www.cnblogs.com/wang_yb/p/3942208.html 主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法. CPU资源控制 每个进 ...

  3. Linux systemd资源控制初探

    Linux systemd资源控制初探 本文记录一次cgroup子目录丢失问题,并简单探索了Linux systemd的资源控制机制. 问题现象 我们希望通过systemd拉起服务并通过cgroup限 ...

  4. Docker的资源控制管理

    Docker的资源控制管理 1.CPU控制 2.对内存使用进行限制 3.对磁盘I/O配额控制的限制 1.CPU控制: cgroups,是一个非常强大的linux内核工具,他不仅可以限制被namespa ...

  5. Identity4实现服务端+api资源控制+客户端请求

    准备写一些关于Identity4相关的东西,最近也比较对这方面感兴趣.所有做个开篇笔记记录一下,以便督促自己下一个技术方案方向 已经写好的入门级别Identity4的服务+api资源访问控制和简单的客 ...

  6. 8.深入k8s:资源控制Qos和eviction及其源码分析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com,源码版本是1.19 又是一个周末,可以愉快的坐下来静静的品味一段源码,这一篇涉及到资源的 ...

  7. 十六、资源控制器之DaemonSet

    资源控制器之DaemonSet DaemonSet 确保全部(或者一些) Node上运行一个 Pod 的副本,当有 Node 加入集群时,也会为他们新增一个 Pod,当有 Node 从集群移除时,这些 ...

  8. 十五、资源控制之Deployment

    资源控制器之Deployment Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationControlle ...

  9. 5.cgroup资源控制

    控制组( CGroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离.限制.审计等. 只有将分配到容器的资源进行控制,才能避免多个容器同时运行时对宿主机系统的资源竞争.每个控制组是一组 ...

随机推荐

  1. 《python 网络数据采集》代码更新

    <python 网络数据采集>这本书中会出现很多这一段代码: 1 from urllib.request import urlopen 2 from bs4 import Beautifu ...

  2. vue知识点11

    1. Vue.js 是什么       Vue是一套用于构建用户界面的渐进式框架 2. vue的环境搭建(Vue2 ) 3. 经典的hello world         new Vue({      ...

  3. JAVA 基于Jusup爬虫

    java爬虫核心:httpclient slf4j jsoup slf4j 配置文件log4j.properties log4j.rootlogger=DEBUG,A1log4j.logger.cn. ...

  4. 第二十七章 ansible变量介绍

    一.ansible变量介绍 1.概念 变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其它地方或许会反复使用,那么如果讲 ...

  5. linux安装日志切割程序

    ====linux安装日志切割程序==== 安装 gcc(1) yum insatll gcc (2)# cd cronolog-1.6.2 4.运行安装 # ./configure# make# m ...

  6. 平时查询linux服务器与应用版本

    ###JDK版本###java -version ##Tomcat环境版本###进入到tomcat目录的bin下./version.sh ###服务器###(1)osuname -a 查看releas ...

  7. Cloudera Manager简介

    Hadoop家族 整个Hadoop家族由以下几个子项目组成: Hadoop Common: Hadoop体系最底层的一个模块,为Hadoop各子项目提供各 种工具,如:配置文件和日志操作等. HDFS ...

  8. 部署SpringBoot项目jar包到云服务器

    前言 做安卓开发也有三四年了,但是对网络这块什么http.tcp/ip之类的一直不理解.并且想自己做一些小项目练练手的时候,数据库直接存在apk里总不是滋味,所以这次站在安卓开发的角度尝试着做一做简单 ...

  9. LORA串口无线数据透明传输终端ZSL311

    ZSL311是由成都众山科技生产销售的一款LORA串口无线数据透明传输终端,采用的是LoRa扩频技术来进行无线数据传输,同时提供RS485和RS232串口,为用户提供全透明数据传输模式.支持星形.Me ...

  10. Git的介绍及使用

    一.配置用户信息: 配置用户名和邮箱: $ git config --global user.name "chunyu" $ git config --global user.em ...