使用CGroups限制硬件资源
Opened this issue · 2 comments
图来自1
CGroups提供了进程级别的资源(CPU、内存、网络和磁盘等)分配机制,也就是可以限制某一个或者某一组进程的资源使用。
为什么需要这么一种技术呢?
如果你了解过docker,那应该知道容器之间是相互安全隔离的,它的底层实现就是采用的CGroups技术。资源隔离是必要的,在同一台机器上运行着非常多的进程,如果这台机器资源是共享给多个用户在使用,你肯定不想因为某个用户的程序负载过大而影响到所有其它用户,这就需要资源安全隔离,避免发生级联错误。再一个也为了保持大家都公平的使用资源,而不会出现一方过多或另一方过少的情况。
CGroup介绍
CGroup是Control Groups 的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物力资源(如cpu memory i/o 等等) 的机制。
CGroup是将任意进程进行分组化管理的 Linux 内核功能。CGroup本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为CGroup子系统或控制器。CGroup 子系统有控制内存的Memory控制器、控制进程调度的CPU控制器等。运行中的内核可以使用的Cgroup子系统由/proc/cgroup 来确认。
CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用 CGroup,必须挂载 CGroup 文件系统。这时通过挂载选项指定使用哪个子系统。
Cgroups提供的功能:
- 限制进程组可以使用的资源数量(Resource limiting )。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
- 进程组的优先级控制(Prioritization )。比如:可以使用cpu子系统为某个进程组分配特定cpu share。
- 记录进程组使用的资源数量(Accounting )。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
- 进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
- 进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。
Cgroup相关概念介绍:
- 任务(task)。在cgroups中,任务就是系统的一个进程;
- 控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用cgroups以控制族群为单位分配的资源,同时受到cgroups以控制族群为单位设定的限制;
- 层级(hierarchy)。控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性;
- 子系统(subsystem)。一个子系统就是一个资源控制器,比如cpu子系统就是控制cpu时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。
相关概念的相互关系:
每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认cgroup(我们称之为root cgroup,此 cgroup 在创建层级时自动创建,后面在该层级中创建的cgrou 都是此cgroup的后代)的初始成员;
一个子系统最多只能附加到一个层级;
一个层级可以附加多个子系统;
一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级;
系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在cgroup的成员。然后可根据需要将该子任务移动到不同的cgroup中,但开始时它总是继承其父任务的cgroup。
由上图所示,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中生成的数据包。
参数介绍
cfs_quota_us 和 cfs_period_us 参数单位是微秒,其中前者是指一个周期内总的可用运行时间,后者是指一个周期的长度,它们可以配合起来限制CPU的运行时间,下面列举几组例子让大家更容易理解。
- cpu.cfs_quota_us=250000、 cpu.cfs_period_us=250000 如果period为250ms且quota为250ms,那么该控制组每250ms将获得1个CPU运行时间。
- cpu.cfs_quota_us=1000000、 cpu.cfs_period_us=500000 如果period为500ms且quota为1000ms,那么该控制组每500ms将获得2个CPU运行时间。
- cpu.cfs_quota_us=10000、 cpu.cfs_period_us=50000 如果period为50ms且quota为10ms,那么该控制组每50ms将获得1个CPU的20%运行时间。
注意
- 可以通过 top 系统命令并查看 %CPU 和 %MEM 列确认目标进程资源是否真的被限制住了,这个百分比只表示单核,如果机器是多核就乘以核数。
- 如果某个控制组已经应用在一个进程上了,那再次使用该控制组将中断原先的进程,你可以通过创建多个控制组来解决这个问题。
实验
[root@localhost bingoohuang]# md5sum /dev/urandom &
[1] 20070
[root@localhost bingoohuang]# top -p 20070
top - 12:28:50 up 1:48, 2 users, load average: 0.50, 0.15, 0.08
Tasks: 291 total, 2 running, 289 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.0 us, 4.5 sy, 0.0 ni, 93.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 65529944 total, 64081524 free, 870492 used, 577928 buff/cache
KiB Swap: 20971516 total, 20971516 free, 0 used. 64157204 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20070 root 20 0 107964 656 532 R 100.0 0.0 0:35.30 md5sum
[root@localhost bingoohuang]# ./cgroup.sh 20070 1
[root@localhost bingoohuang]# top -n 20070
top - 12:37:01 up 1:56, 2 users, load average: 0.00, 0.12, 0.12
Tasks: 291 total, 2 running, 289 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.5 us, 0.9 sy, 0.0 ni, 98.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 65529944 total, 64081096 free, 869704 used, 579144 buff/cache
KiB Swap: 20971516 total, 20971516 free, 0 used. 64157520 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20070 root 20 0 107964 656 532 R 15.9 0.0 4:03.96 md5sum
cgroup.sh:
#!/bin/bash
# https://github.com/the7winds/aucont/blob/3eef6efedfbad428227338b8cd1beca293947f7e/src/cgroup.sh
pid=$1
perc=$2
cores=`nproc`
period=1000000
let 'quota=period*cores*perc/100'
cgdir=/sys/fs/cgroup/cpu/$pid
mkdir -p $cgdir
echo $pid > $cgdir/tasks
echo $period > $cgdir/cpu.cfs_period_us
echo $quota > $cgdir/cpu.cfs_quota_us
cpu_cg_setup.sh:
#!/bin/bash
# https://github.com/wtf42/au-containers/blob/226f46f4bd2f67703e8f38de74867d93f0a69705/tools/src/scripts/cpu_cg_setup.sh
CONT_PID=$1
QUOTA=$2
# Working Directory
WD=$3
CGMOUNT=$WD/.cg_cpu
CGDIR=$CGMOUNT/aucont
CONT_CGDIR=$CGDIR/$CONT_PID
CG_TYPE=$(lssubsys -a | grep -w "cpu" || echo "cpu")
mkdir -p $CGMOUNT
mountpoint -q $CGMOUNT || sudo mount -t cgroup -o $CG_TYPE aucont_cpu_cg $CGMOUNT
sudo mkdir -p $CGDIR
echo "CGDIR:$CGDIR"
sudo chown -R $(id -u):$(id -g) $CGDIR
mkdir -p $CONT_CGDIR
echo $CONT_PID > $CONT_CGDIR/tasks
# NPROC=$(nproc)
CG_PERIOD=1000000
# CG_QUOTA=$((CG_PERIOD * NPROC * QUOTA / 100))
CG_QUOTA=$((CG_PERIOD * QUOTA / 100))
echo $CG_PERIOD > $CONT_CGDIR/cpu.cfs_period_us
echo $CG_QUOTA > $CONT_CGDIR/cpu.cfs_quota_us
资源限制测试
对IO限制进行测试
消耗IO命令行:
- dd if=/dev/sda of=/dev/null 使用iotop工具进行查看。
- Simulating high CPU usage : sha1sum /dev/zero &
- killall sha1sum
对内存限制进行测试
消耗内存的mysql脚本文件:
x='a'
while [ True ];do
x=$x$x
done;
使用top工具进行查看。(跑消耗内存的脚本文件命令窗口直接关闭)
对CPU限制进行测试
运用mysqlslap性能测试工具对已安装的mysql进行压力测试
mysqlslap?--concurrency(并发数量)=150?--iterations(测试次数)=1?--number-int-cols(创建测试表的int型字段数量)=8?
--auto-generate-sql(用系统生成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
对进程带宽限制进行测试
用iperf指令进行打流,运用cgroup和tc进行流控。
参考资源
- Limit memory usage for a single Linux process
cgcreate -g memory:myGroup echo 500M > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes echo 5G > /sys/fs/cgroup/memory/myGroup/memory.memsw.limit_in_bytes cgexec -g memory:myGroup pdftoppm
- 视频笔记:容器是什么?让我们用 Go 写一个吧! - Liz Rice
- stress, 生成指定cpu压力和内存占用a tool for maing cpu load and memory usage with specified ratio
- 在CentOS上使用CGroups隔离硬件资源
- Linux下cGroup调研.docx
- 资源限制测试.txt
- execc is a simple example of a container runtime. It simply runs a command in a container. It uses the cgcreate, cgexec, cgset, cgdelete, unshare, and chroot commands to initialize the container.
Run a shell in a busybox container limited to 100 milli-cores and 1 megabyte of memory.$ mkdir rootfs $ docker export $(docker create busybox) | gzip -c > busybox.tar.gz $ sudo execc -c 100 -m 1000000 --rootfs busybox.tar.gz /bin/sh / # echo "Hello from inside a container!" Hello from inside a container! #
- github cfs_period_us search
- github cgexec search
- Linux的cgroup功能(二):资源限制cgroup v1和cgroup v2的详细介绍
- docker 容器基础技术:linux cgroup 简介
- cgexec - Execute commands in a Linux Control Group (cgroups v2)
- cgroup-v1
As an example of a scenario (originally proposed by vatsa@in.ibm.com) that can benefit from multiple hierarchies, consider a large university server with various users - students, professors, system tasks etc. The resource planning for this server could be along the following lines: CPU : "Top cpuset" / \ CPUSet1 CPUSet2 | | (Professors) (Students) In addition (system tasks) are attached to topcpuset (so that they can run anywhere) with a limit of 20% Memory : Professors (50%), Students (30%), system (20%) Disk : Professors (50%), Students (30%), system (20%) Network : WWW browsing (20%), Network File System (60%), others (20%) / \ Professors (15%) students (5%)
```
我不记得了,并且不认为在unix调度程序中有这样的东西。 您需要一个控制其他进程的小程序,并执行以下操作:
loop
wait for some time tR
send SIGSTOP to the process you want to be scheduled
wait for some time tP
send SIGCONT to the process.
loopEnd
比率tR / tP控制cpu负载。
这是一个小概念证明。 “忙”是一个耗尽你的cpu时间的程序,你希望通过“slowDown”减慢你的速度:
> cat > busy.c:
main() { while (1) {}; }
> cc -o busy busy.c
> busy &
> top
Tasks: 192 total, 3 running, 189 sleeping, 0 stopped, 0 zombie
Cpu(s): 76.9% us, 6.6% sy, 0.0% ni, 11.9% id, 4.5% wa, 0.0% hi, 0.0% si
Mem: 6139696k total, 6114488k used, 25208k free, 115760k buffers
Swap: 9765368k total, 1606096k used, 8159272k free, 2620712k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26539 cg 25 0 2416 292 220 R 90.0 0.0 3:25.79 busy
...
> cat > slowDown
while true; do
kill -s SIGSTOP $1
sleep 0.1
kill -s SIGCONT $1
sleep 0.1
done
> chmod +x slowDown
> slowDown 26539 &
> top
Tasks: 200 total, 4 running, 192 sleeping, 4 stopped, 0 zombie
Cpu(s): 48.5% us, 19.4% sy, 0.0% ni, 20.2% id, 9.8% wa, 0.2% hi, 2.0% si
Mem: 6139696k total, 6115376k used, 24320k free, 96676k buffers
Swap: 9765368k total, 1606096k used, 8159272k free, 2639796k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26539 cg 16 0 2416 292 220 T 49.7 0.0 6:00.98 busy
...
好吧,那个脚本需要更多的工作(例如,要关心INTR-up,并让受控过程继续,以防它在那一刻被停止),但你明白了。 我也会在C或类似的地方编写那个小脚本,并从命令行参数计算cpu比率....
用 docker 执行 while 循环,演示 CPU CGroup
运行一个 busybox 容器,并限制只允许使用 20% 的 CPU,while 循环可以模拟跑满 CPU,操作如下:
[root@centos ~]# docker run -d --cpu-period=100000 --cpu-quota=20000 --name busybox busybox:1.29.3 /bin/sh -c "while : ; do : ; done"
52f0ea4715b26f56bb27b46aedaaa326c24040afe520f840e18ace3f7bf99e19
查看宿主机 top
[root@centos ~]# top
top - 17:36:55 up 1:53, 1 user, load average: 0.01, 0.06, 0.16
Tasks: 99 total, 2 running, 97 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 7.3 us, 13.0 sy, 0.0 ni, 79.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3881016 total, 3492996 free, 146688 used, 241332 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3475308 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4517 root 20 0 1236 4 0 R 20.3 0.0 0:06.48 sh
查看 /sys/fs/cgroup
[root@centos ~]# cat /sys/fs/cgroup/cpu/system.slice/docker-52f0ea4715b26f56bb27b46aedaaa326c24040afe520f840e18ace3f7bf99e19.scope/cpu.cfs_period_us
100000
[root@centos ~]# cat /sys/fs/cgroup/cpu/system.slice/docker-52f0ea4715b26f56bb27b46aedaaa326c24040afe520f840e18ace3f7bf99e19.scope/cpu.cfs_quota_us
20000
最后记得关闭 busybox 容器
[root@centos ~]# docker container rm -f busybox
作者:ConanLi
链接:https://www.jianshu.com/p/4199e63cf472