在Linux中使用cgroups和slice分配资源的步骤及示例

时间:2020-01-09 10:37:28  来源:igfitidea点击:

在Linux上使用fstab和systemd来更改/dev/shm,/run和其他文件的tmpfs分区大小。

现在从本文开始," cgroup"或者" Control Group"为进程组提供资源管理和资源核算。就性能而言,Cgroups内核的实现大多位于非关键路径上。 cgroups子系统实现了一个名为"cgroups"的新虚拟文件系统(VFS)类型。所有cgroup操作都是通过文件系统操作完成的,例如在cgroup文件系统中创建cgroups目录,写入或者读取这些目录中的条目,安装cgroup文件系统等。

cgroups上的指针很少

  • 自kernel 2.6.24以来,cgroup现在已与systemd集成在最新的Linux版本中。

  • 控制组将资源放置在代表资源类型的控制器中,即,我们可以定义可用资源组,以确保应用程序(例如Web服务器)对资源有保证

  • 为了做到这一点,cgroup与默认控制器一起使用,它们是cpumemoryblkio

  • 这些控制器分为树形结构,其中对每个分支应用不同的权重或者限制

  • 这些分支中的每一个都是一个cgroup

  • 一个或者多个进程分配给一个cgroup

  • cgroups可以从命令行或者systemd来应用

  • 手动创建是通过cgconfig服务和cgred过程进行的

  • 在所有情况下,cgroup设置都被写入/sys/fs/cgroups中。

# ls -l /sys/fs/cgroup/
total 0
drwxr-xr-x 2 root root  0 Nov 26 12:48 blkio
lrwxrwxrwx 1 root root 11 Nov 26 12:48 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Nov 26 12:48 cpuacct -> cpu,cpuacct
drwxr-xr-x 2 root root  0 Nov 26 12:48 cpu,cpuacct
drwxr-xr-x 2 root root  0 Nov 26 12:48 cpuset
drwxr-xr-x 3 root root  0 Nov 26 12:50 devices
drwxr-xr-x 2 root root  0 Nov 26 12:48 freezer
drwxr-xr-x 2 root root  0 Nov 26 12:48 hugetlb
drwxr-xr-x 2 root root  0 Nov 26 12:48 memory
lrwxrwxrwx 1 root root 16 Nov 26 12:48 net_cls -> net_cls,net_prio
drwxr-xr-x 2 root root  0 Nov 26 12:48 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Nov 26 12:48 net_prio -> net_cls,net_prio
drwxr-xr-x 2 root root  0 Nov 26 12:48 perf_event
drwxr-xr-x 2 root root  0 Nov 26 12:48 pids
drwxr-xr-x 4 root root  0 Nov 26 12:48 systemd

这些是内核本身创建的不同的"控制器"。例如,每个控制器都有自己的"可调参数"

# ls -l /sys/fs/cgroup/cpuacct/
total 0
-rw-r--r-- 1 root root 0 Nov 26 12:48 cgroup.clone_children
--w--w---- 1 root root 0 Nov 26 12:48 cgroup.event_control
-rw-r--r-- 1 root root 0 Nov 26 12:48 cgroup.procs
-r--r--r-- 1 root root 0 Nov 26 12:48 cgroup.sane_behavior
-r--r--r-- 1 root root 0 Nov 26 12:48 cpuacct.stat
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpuacct.usage
-r--r--r-- 1 root root 0 Nov 26 12:48 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Nov 26 12:48 cpu.shares
-r--r--r-- 1 root root 0 Nov 26 12:48 cpu.stat
-rw-r--r-- 1 root root 0 Nov 26 12:48 notify_on_release
-rw-r--r-- 1 root root 0 Nov 26 12:48 release_agent
-rw-r--r-- 1 root root 0 Nov 26 12:48 tasks

了解切片

默认情况下,systemd自动创建切片,作用域和服务单元的层次结构,以为cgroup树提供统一的结构。服务,范围和切片由系统管理员手动创建,或者由程序动态创建。默认情况下,操作系统定义了一些运行系统所需的内置服务。另外,默认情况下会创建四个切片:

  • -.slice-根切片;

  • system.slice-所有系统服务的默认位置;

  • user.slice-所有用户会话的默认位置;

  • machine.slice-所有虚拟机和Linux容器的默认位置。

在分片中如何分配资源?

让我们以" CPUShares"为例。

现在假设我们将以下" CPUShares"的值分配给以下切片

system.slice -> 1024
user.slice -> 256
machine.slice -> 2048

这些值是什么意思?

实际上,它们实际上没有任何意义,而是将这些值用作所有切片之间的比较因子。其中:如果我们假设总CPU可用性为" 100%",那么" user.slice"将获得"~7%"," system.slice"将获得" user.slice"分配的4倍,即"~30%" 和machine.slice将获得两倍于system.slice的分配,这大约是可用CPU资源的~60%。

如果我在system.slice中创建多个服务怎么办?

假设我在system.slice内部创建了三个具有CPUShares值的服务,如下所示,这是一个有效的问题

service1 -> 1024
service2 -> 256
service3 -> 512

如果加起来,总数将大于1024,在上述示例中,该总数实际上已分配给system.slice。再一次,这些值仅是比较的意思,实际上没有任何意义。其中:" service1"将获得最大的可用资源量,即,如果" system.slice"的资源的" 100%"可用,则" service1"将获得"~56%"," service2"将获得~14%service3将获得可用CPU的~28%

"这就是大级别的此cgroup设置如何在不同片之间以及不同片之间与不同服务之间的关系。

如何创建自定义切片?

  • 切片单元的每个名称都对应于层次结构中某个位置的路径。

  • 子片将继承父片的设置。

  • 破折号(-)充当路径组件的分隔符。

例如,如果切片的名称如下所示:

parent-name.slice

这意味着称为" parent-name.slice"的片是" parent.slice"的子片。该片可以具有其自己的名为" parent-name-name2.slice"的子片,依此类推。

使用示例测试资源分配

现在,我们将创建两个systemd单位文件,即stress1.servicestress2.service。这些服务脚本将利用我系统上的所有CPU

说明:

为了演示,我禁用了所有其他CPU,并且仅启用了一个CPU。因为如果我们有多个CPU,那么负载将被分配,而我将无法显示CPUShares的资源分配。

使用这些systemd单位文件,我将使用system.slice来放置一些CPU负载。

# cat /etc/systemd/system/stress1.service
[Unit]
Description=Put some stress
[Service]
Type=Simple
ExecStart=/usr/bin/dd if=/dev/zero of=/dev/null

这是我的第二个单位文件,具有相同的内容以向CPU施加压力

# cat /etc/systemd/system/stress2.service
[Unit]
Description=Put some stress
[Service]
Type=Simple
ExecStart=/usr/bin/dd if=/dev/zero of=/dev/null

启动这些服务

# systemctl daemon-reload
# systemctl start stress1
# systemctl start stress1

现在使用" top"命令验证CPU使用率

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 1994 root      20   0  107992    608    516 R 49.7  0.0   0:03.11 dd
 2001 root      20   0  107992    612    516 R 49.7  0.0   0:02.21 dd

如我们所见,由于有两个进程都在系统切片中,因此我有两个进程正在尝试利用可用的CPU,该进程同样会获取可用资源。因此,两个进程都按预期获得了CPU的~50%。

现在,让我们尝试在后台使用while命令在user.slice上添加一个新进程。

# while true; do true; done &

接下来检查CPU使用情况,现在按预期将"可用CPU分为3个进程"。在user.slice和system.slice之间没有区别

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 1983 root      20   0  116220   1404    152 R 32.9  0.0   1:53.28 bash
 2193 root      20   0  107992    608    516 R 32.9  0.0   0:07.59 dd
 2200 root      20   0  107992    612    516 R 32.9  0.0   0:07.13 dd

说明:

其中:我们看到用户和系统切片级进程都获得了相等数量的可用资源,这是因为默认情况下,我们的发行版中的DefaultCPUAccounting,DefaultBlockIOAccounting和DefaultMemoryAccounting处于禁用状态。

现在,让我们通过启用/etc/systemd/system.conf中的以下值来启用切片

DefaultCPUAccounting=yes
DefaultBlockIOAccounting=yes
DefaultMemoryAccounting=yes

重新启动节点以激活更改

重要的提示:

重新启动节点以激活更改很重要。

一旦系统恢复启动,接下来我们将再次使用bash shell启动" stress1"和" stress2"服务以及一个" while循环"。

# systemctl start stress1
# systemctl start stress2
# while true; do true; done &

现在使用" top"命令验证CPU使用率

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 2132 root      20   0  116220   1520    392 R 49.3  0.0   1:16.47 bash
 1994 root      20   0  107992    608    516 R 24.8  0.0   2:30.40 dd
 2001 root      20   0  107992    612    516 R 24.8  0.0   2:29.50 dd

如我们所见,我们的切片已生效。现在,用户分片可以要求" CPU的50%",而系统分片则为两种压力服务分配"~25%"的资源。

现在让我们使用" CPUShares"为系统单元文件进一步预留CPU。

# cat /etc/systemd/system/stress2.service
[Unit]
Description=Put some stress
[Service]
CPUShares=1024
Type=Simple
ExecStart=/usr/bin/dd if=/dev/zero of=/dev/null
# cat /etc/systemd/system/stress1.service
[Unit]
Description=Put some stress
[Service]
CPUShares=512
Type=Simple
ExecStart=/usr/bin/dd if=/dev/zero of=/dev/null

现在,在上面的单元文件中,我将优先级指定为Stress2.service,以便将分配给Stress1.service的资源加倍。

说明:

CPUShares的允许范围是2到262144. 默认值为1024.

接下来重启服务

# systemctl daemon-reload
# systemctl restart stress1
# systemctl restart stress2

验证" top"输出

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 2132 root      20   0  116220   1520    392 R 49.7  0.0   2:43.11 bash
 2414 root      20   0  107992    612    516 R 33.1  0.0   0:04.85 dd
 2421 root      20   0  107992    608    516 R 16.6  0.0   0:01.95 dd

因此,正如预期的那样,在system.slice可用的" 50%" CPU资源中," stress2"获得了分配给" stress1"服务的CPU的"两倍"。

说明:

如果没有从" user.slice"运行的活动进程,则" system.slice"将被允许使用高达100%的可用CPU资源。

监控每片的资源使用情况

" systemd-cgtop"显示了本地Linux控制组层次结构中的顶级控制组,按其" CPU","内存"或者"磁盘I/O"负载排序。显示屏会定期刷新(默认情况下每1秒刷新一次),其样式类似于top命令。资源使用仅考虑相关层次结构中的控制组,即" CPU使用率"仅考虑cpuacct层次结构中的控制组,"内存"使用仅用于内存中的控制组,"磁盘I/O"使用对于blkio中的控制组。

Path                                                                               Tasks   %CPU   Memory  Input/s Output/s
/                                                                                    56  100.0   309.0M        -        
/system.slice                                                                          -   97.5   277.4M        -        
/system.slice/stress3.service                                                          1   59.9   104.0K        -        
/system.slice/stress1.service                                                          1   29.9   104.0K        -        
/system.slice/stress2.service                                                          1    7.5   108.0K        -        
/user.slice                                                                            -    1.7    10.7M        -        
/user.slice/user-0.slice                                                               -    1.7    10.4M        -        
/user.slice/user-0.slice/session-7.scope                                               3    1.7     4.6M        -        
/system.slice/pacemaker.service                                                        7    0.0    41.6M        -        
/system.slice/pcsd.service                                                             1    0.0    46.8M        -        
/system.slice/fail2ban.service                                                         1    0.0     9.0M        -        
/system.slice/dhcpd.service                                                            1    0.0     4.4M        -        
/system.slice/tuned.service                                                            1    0.0    11.8M        -        
/system.slice/NetworkManager.service                                                   3    0.0    11.3M        -        
/system.slice/httpd.service                                                            6    0.0     4.6M        -        
/system.slice/abrt-oops.service                                                        1    0.0     1.4M        -        
/system.slice/rsyslog.service                                                          1    0.0     1.5M        -        
/system.slice/rngd.service                                                             1    0.0   176.0K        -        
/system.slice/ModemManager.service                                                     1      -     3.6M        -        
/system.slice/NetworkManager-dispatcher.service                                        1      -   944.0K        -