转载自:https://jin-yang.github.io/post/linux-container-cgroup-introduce.html

在 CentOS 7 中,已经通过 systemd 替换了之前的 cgroup-tools 工具,为了防止两者冲突,建议只使用 systemd ,只有对于一些不支持的,例如 net_prio ,才使用 cgroup-tools 工具。

在此,简单介绍其使用。

简介

在系统设计时,经常会遇到类似的需求,就是希望能限制某个或者某些进程的分配资源。

由此,就有了容器的概念,在容器中,有分配好的特定比例的 CPU、IO、内存、网络等资源,这就是 controller group ,简称为 cgroup ,最初由 Google 工程师提出,后来被整合进 Linux 内核中。

cgroup 本身提供了将进程进行分组化管理的功能和接口的基础结构。

使用简介

在 CentOS 7 中需要通过 yum install libcgroup libcgroup-tools 安装额外的 cgroup 工具,对系统来说,默认会挂载到 /sys/fs/cgroup/ 目录下。

----- 查看系统已经存在cgroup子系统及其挂载点
# lssubsys -am
----- 或者通过mount查看cgroup类型的挂载点
# mount -t cgroup----- 可以命令行挂载和卸载子系统,此时再次执行上述命令将看不到memory挂载点
# umount /sys/fs/cgroup/memory/
----- 挂载cgroup的memory子系统,其中最后的cgroup参数是在/proc/mounts中显示的名称
# mount -t cgroup -o memory cgroup /sys/fs/cgroup/memory/
# mount -t cgroup -o memory none /sys/fs/cgroup/memory/

另外,在 CentOS 中有 /etc/cgconfig.conf 配置文件,该文件中可用来配置开机自动启动时挂载的条目:

mount {net_prio = /sys/fs/cgroup/net_prio;
}

然后,通过 systemctl restart cgconfig.service 重启服务即可,然后可以通过如下方式使用。

使用步骤

简单介绍如何通过 libcgroup-tools 创建分组并设置资源配置参数。

1. 创建控制组群

可以通过如下方式创建以及删除群组,创建后会在 cpu 挂载目录下 /sys/fs/cgroup/cpu/ 目录下看到一个新的目录 test,这个就是新创建的 cpu 子控制组群。

# cgcreate -g cpu:/test
# cgdelete -g cpu:/test

2. 设置组群参数

cpu.shares 是控制 CPU 的一个属性,更多的属性可以到 /sys/fs/cgroup/cpu 目录下查看,默认值是 1024,值越大,能获得更多的 CPU 时间。

# cgset -r cpu.shares=512 test

3. 将进程添加到控制组群

可以直接将需要执行的命令添加到分组中。

----- 直接在cgroup中执行
# cgexec -g cpu:small some-program
----- 将现有的进程添加到cgroup中
# cgclassify -g subsystems:path_to_cgroups pidlist

例如,想把 sshd 添加到一个分组中,可以通过如下方式操作。

# cgclassify -g cpu:/test `pidof sshd`
# cat /sys/fs/cgroup/cpu/test/tasks

就会看到相应的进程在这个文件中。

CPU

在 CGroup 中,与 CPU 相关的子系统有 cpusets、cpuacct 和 cpu 。

  • CPUSET 用于设置CPU、内存的亲和性,可以指定运行CPU或者不运行在某个CPU上,一般只会在一些高性能场景使用。
  • CPUACCT 显示当前cgroup所用CPU的统计信息。

这里简单介绍 cpu 子系统,包括怎么限制 cgroup 的 CPU 使用上限及与其它 cgroup 的相对值。

cpu.cfs_period_us & cpu.cfs_quota_us

其中 cfs_period_us 用来配置时间周期长度;cfs_quota_us 用来配置当前 cgroup 在设置的周期长度内所能使用的 CPU 时间数,两个文件配合起来设置 CPU 的使用上限。

两个文件单位是微秒,cfs_period_us 的取值范围为 [1ms, 1s],默认 100ms ;cfs_quota_us的取值大于 1ms 即可,如果 cfs_quota_us 的值为 -1(默认值),表示不受 cpu 时间的限制。

下面是几个例子:

----- 1.限制只能使用1个CPU,每100ms能使用100ms的CPU时间
# echo 100000 > cpu.cfs_quota_us
# echo 100000 > cpu.cfs_period_us------ 2.限制使用2个CPU核,每100ms能使用200ms的CPU时间,即使用两个内核
# echo 200000 > cpu.cfs_quota_us
# echo 100000 > cpu.cfs_period_us------ 3.限制使用1个CPU的50%,每100ms能使用50ms的CPU时间,即使用一个CPU核心的50%
# echo 50000 > cpu.cfs_quota_us
# echo 100000 > cpu.cfs_period_us

cpu.shares

用于设置相对值,这里针对的是所有 CPU (多核),默认是 1024,假如系统中有两个 A(1024) 和 B(512),那么 A 将获得 1024/(1204+512)=66.67% 的 CPU 资源,而 B 将获得 33% 的 CPU 资源。

对于 shares 有两个特点:

  • 如果A不忙,没有使用到66%的CPU时间,那么剩余的CPU时间将会被系统分配给B,即B的CPU使用率可以超过33%;
  • 添加了一个新的C,它的shares值是1024,那么A和C的限额变为1024/(1204+512+1024)=40%,B的资源变成了20%;

也就是说,在空闲时 shares 基本上不起作用,只有在 CPU 忙的时候起作用。但是这里设置的值是需要与其它系统进行比较,而非设置了一个绝对值。

示例

演示一下如何控制CPU的使用率。

----- 创建并查看当前的分组
# cgcreate -g cpu:/small
# ls /sys/fs/cgroup/cpu/small----- 查看当前值,默认是1024
# cat /sys/fs/cgroup/cpu/small/cpu.shares
# cgset -r cpu.shares=512 small----- 执行需要运行的程序,或者将正在运行程序添加到分组
# cgexec -g cpu:small ./foobar
# cgclassify -g cpu:small <PID>----- 设置只能使用1个cpu的20%的时间
# echo 50000 > cpu.cfs_period_us
# echo 10000 > cpu.cfs_quota_us----- 将当前bash加入到该cgroup
# echo $$
5456
# echo 5456 > cgroup.procs----- 启动一个bash内的死循环,正常情况下应该使用100%的cpu,消耗一个核
# while :; do echo test > /dev/null; done

注意,如果是在启动进程之后添加的,实际上 CPU 资源限制的速度会比较慢,不是立即就会限制死的,而且不是严格准确。如果起了多个子进程,那么各个进程之间的资源是共享的。

其它

可以通过如下命令查看进程属于哪个 cgroup 。

# ps -O cgroup
# cat /proc/PID/cgroup

内存

相比来说,内存控制要简单的多,只需要注意物理内存和 SWAP 即可。

----- 创建并查看当前的分组
# cgcreate -g memory:/small
# ls /sys/fs/cgroup/memory/small----- 查看当前值,默认是一个很大很大的值,设置为1M
# cat /sys/fs/cgroup/memory/small/memory.limit_in_bytes
# cgset -r memory.limit_in_bytes=10485760 small----- 如果开启了swap之后,会发现实际上内存只限制了RSS,设置时需要确保没有进程在使用
# cgset -r memory.memsw.limit_in_bytes=104857600 small----- 启动测试程序
# cgexec -g cpu:small -g memory:small ./foobar
# cgexec -g cpu,memory:small ./foobar

OOM

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

----- 关闭默认的OOM
# echo 1 > memory.oom_control
# cgset -r memory.oom_control=1 small

注意,及时关闭了 OOM,对应的进程会处于 uninterruptible sleep 状态。

systemd

CentOS 7 中默认的资源隔离是通过 systemd 进行资源控制的,systemd 内部使用 cgroups 对其下的单元进行资源管理,包括 CPU、BlcokIO 以及 MEM,通过 cgroup 可以 。

systemd 的资源管理主要基于三个单元 service、scope 以及 slice:

  • service
    通过 unit 配置文件定义,包括了一个或者多个进程,可以作为整体启停。
  • scope
    任意进程可以通过 fork() 方式创建进程,常见的有 session、container 等。
  • slice
    按照层级对 service、scope 组织的运行单元,不单独包含进程资源,进程包含在 service 和 scope 中。

常用的 slice 有 A) system.slice,系统服务进程可能是开机启动或者登陆后手动启动的服务,例如crond、mysqld、nginx等服务;B) user.slice 用户登陆后的管理,一般为 session;C) machine.slice 虚机或者容器的管理。

对于 cgroup 默认相关的参数会保存在 /sys/fs/cgroup/ 目录下,当前系统支持的 subsys 可以通过 cat /proc/cgroups 或者 lssubsys 查看。

常见命令

常用命令可以参考如下。

----- 查看slice、scope、service层级关系
# systemd-cgls----- 当前资源使用情况
# systemd-cgtop----- 启动一个服务
# systemd-run --unit=name --scope --slice=slice_name commandunit   用于标示,如果不使用会自动生成一个,通过systemctl会输出;scope  默认使用service,该参数指定使用scope ;slice  将新启动的service或者scope添加到slice中,默认添加到system.slice,也可以添加到已有slice(systemctl -t slice)或者新建一个。
# systemd-run --unit=toptest --slice=test top -b
# systemctl stop toptest----- 查看当前资源使用状态
$ systemctl show toptest

各服务配置保存在 /usr/lib/systemd/system/ 目录下,可以通过如下命令设置各个服务的参数。

----- 会自动保存到配置文件中做持久化
# systemctl set-property name parameter=value----- 只临时修改不做持久化
# systemctl set-property --runtime name property=value----- 设置CPU和内存使用率
# systemctl set-property httpd.service CPUShares=600 MemoryLimit=500M

另外,在 213 版本之后才开始支持 CPUQuota 参数,可直接修改 cpu.cfs_{quota,period}_us 参数,也就是在 /sys/fs/cgroup/cpu/ 目录下。

libcgroup

基于 libcgroup 实现一套容器的管理,详细的文档可以参考 libcg Documentation 中的相关介绍。

可以参考 Github - cgfy 中的实现,该程序是通过 libcgroup 实现,功能类似于 cgexec 。

另外,也可以参考 Github - clique,是直接利用 DBus 与 Systemd 进行通讯。

参考

关于 systemd 的资源控制,详细可以通过 man 5 systemd.resource-control 命令查看帮助,或者查看 systemd.resource-control 中文手册;详细的内容可以参考 Resource Management Guide 。

容器之 CGroup相关推荐

  1. Docker容器之cgroup搭建

    一.知识剖析 什么是cgroup Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制.记录.隔离进程组(process groups)所使用的物理资源(如 ...

  2. Docker容器之macvlan网络

    Docker容器之macvlan网络 一.查看当前dokcer的版本 二.创建macvlan网络 三.查看现有网络类型 四.运行macvlan网络类型的容器 一.查看当前dokcer的版本 [root ...

  3. Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...

  4. [知识点]C++中STL容器之set

    零.STL目录 1.容器之map 2.容器之vector 3.容器之set 一.前言 继上期的vector之后,我们又迎来了另一个类数组的STL容器--set. 二.用途与特性 set,顾名思义,集合 ...

  5. Docker容器之compose容器集群的快速编排

    Docker容器之compose容器集群的快速编排 前言 一.Docker-compose简介 二.YAML文件格式及编写注意事项 (1)YAML文件格式 (2)YAML格式的注意事项 (3)YAML ...

  6. Docker容器之harbor私有仓库部署与管理

    Docker容器之harbor私有仓库部署与管理 前言 一.Harbor概述 二.Harbor的特性 三.Harbor的构成 四.Harbor私有仓库搭建 (1)安装docker-compose (2 ...

  7. STL源码剖析(十三)关联式容器之rb_tree

    STL源码剖析(十三)关联式容器之rb_tree 文章目录 STL源码剖析(十三)关联式容器之rb_tree 一.rb_tree的数据结构 二.rb_tree的迭代器 三.rb_tree的操作 3.1 ...

  8. 【转】Java并发编程:并发容器之ConcurrentHashMap

    JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了 ...

  9. 企业运维容器之 docker仓库

    企业运维容器之 docker 仓库 1. 什么是仓库? 2. Docker hub 3. Registry 工作原理 4. 配置镜像加速器 5. 搭建私有仓库 5. 总结 1. 什么是仓库? Dock ...

最新文章

  1. DotNet Core Console 程序使用NLog
  2. 中国地图_铜板画地图铜地球仪高档办公室装饰用品定制铜版画地图中国地图世界地图定制惠风堂铜雕艺术...
  3. idea 报错javax/xml/bind/DatatypeConverter
  4. android记账软件开发源代码_如何开发直播软件?直播软件开发的具体流程有哪些?...
  5. Linux有关Shell中if用法笔记
  6. svn服务器如何扫描文件,基于文件仓库进行建模协作(EA+SVN)
  7. 【LeetCode】剑指 Offer 45. 把数组排成最小的数
  8. 怎么理解python循环_如何理解Python的循环设计
  9. 最简单的基于FFMPEG的图像编码器(YUV编码为JPEG)
  10. 非常全面的SVM理论加实践的讲解
  11. python调用cplex_python 调用cplex(设置 CPLEX 的 Python API)
  12. 读取 system serial number
  13. Termux-API 使用教程,很多坑,电量,设备信息
  14. 破解wifi密码最简单教程 就三步
  15. c语言标准差公式标准差数组,Excel标准差计算函数Stdev和StdevP的用法与区别,包含4个实例...
  16. 什么是BOM?BOM和DOM的区别
  17. 基于SSL/TLS双向安全连接设备CA证书认证
  18. 阿里云不同账号新旧服务器镜像迁移数据迁移同步
  19. 小白学python-决策树和随机森林
  20. 申论公文题-方案类-1

热门文章

  1. span按钮disabled属性无效
  2. Swift之深入解析内存安全
  3. 模电--运算放大器工作原理
  4. 吃货联盟(基于mysql)
  5. tensorflow函数中minimize()函数
  6. Unity-场景-Sky
  7. 使用WampServer搭建php开发环境
  8. [图形图像 python]位图切割
  9. 复合维生素的功效和作用是哪些?每天吃维生素有什么好处?
  10. android压感补充