Original link: in-depth understanding of Linux Cgroup series (two): Fun CPU
The article introduces some basic concepts cgroup, including its CentOS
default settings and system control tool, and the CPU example to explain how cgroup resource control. This article will demonstrate how to cgroup be limited by the specific examples of CPU
the impact of using different cgroup and set on performance.
1. Review current information cgroup
There are two ways to view the system's current cgroup information. The first method is through systemd-cgls
to view the command, it will return to the system as a whole cgroup hierarchy tree from the top cgroup slice
composed as follows:
$ systemd-cgls --no-page
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
├─user.slice
│ ├─user-1000.slice
│ │ └─session-11.scope
│ │ ├─9507 sshd: tom [priv]
│ │ ├─9509 sshd: tom@pts/3
│ │ └─9510 -bash
│ └─user-0.slice
│ └─session-1.scope
│ ├─ 6239 sshd: root@pts/0
│ ├─ 6241 -zsh
│ └─11537 systemd-cgls --no-page
└─system.slice
├─rsyslog.service
│ └─5831 /usr/sbin/rsyslogd -n
├─sshd.service
│ └─5828 /usr/sbin/sshd -D
├─tuned.service
│ └─5827 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
├─crond.service
│ └─5546 /usr/sbin/crond -n
Cgroup can see the system level by the highest level user.slice
and system.slice
composition. Because the system does not run virtual machines and containers, so there is no machine.slice
, so when the CPU is busy, user.slice
and system.slice
will each receive 50%
CPU usage time.
user.slice following two sub-slice: user-1000.slice
and user-0.slice
, each sub-slice ID are used the User ( UID
) to name, so it is easy to recognize which slice belongs to which user. For example: From the above it can be seen in the output information user-1000.slice
belongs to the user tom, user-0.slice
belonging to the users root.
systemd-cgls
Command provides only a static snapshot of information cgroup hierarchy, in order to view the cgroup hierarchy of dynamic information, you can systemd-cgtop
view the command:
$ systemd-cgtop
Path Tasks %CPU Memory Input/s Output/s
/ 161 1.2 161.0M - -
/system.slice - 0.1 - - -
/system.slice/vmtoolsd.service 1 0.1 - - -
/system.slice/tuned.service 1 0.0 - - -
/system.slice/rsyslog.service 1 0.0 - - -
/system.slice/auditd.service 1 - - - -
/system.slice/chronyd.service 1 - - - -
/system.slice/crond.service 1 - - - -
/system.slice/dbus.service 1 - - - -
/system.slice/gssproxy.service 1 - - - -
/system.slice/lvm2-lvmetad.service 1 - - - -
/system.slice/network.service 1 - - - -
/system.slice/polkit.service 1 - - - -
/system.slice/rpcbind.service 1 - - - -
/system.slice/sshd.service 1 - - - -
/system.slice/system-getty.slice/[email protected] 1 - - - -
/system.slice/systemd-journald.service 1 - - - -
/system.slice/systemd-logind.service 1 - - - -
/system.slice/systemd-udevd.service 1 - - - -
/system.slice/vgauthd.service 1 - - - -
/user.slice 3 - - - -
/user.slice/user-0.slice/session-1.scope 3 - - - -
/user.slice/user-1000.slice 3 - - - -
/user.slice/user-1000.slice/session-11.scope 3 - - - -
/user.slice/user-1001.slice/session-8.scope 3 - - - -
Statistics provided by systemd-cgtop and control options with the top
command but the command displays only those resources slice open the service and statistical functions. For example: If you want to open the sshd.service
resource statistics function, you can do the following:
$ systemctl set-property sshd.service CPUAccounting=true MemoryAccounting=true
This command will /etc/systemd/system/sshd.service.d/
create the appropriate configuration file directory:
$ ll /etc/systemd/system/sshd.service.d/
总用量 8
4 -rw-r--r-- 1 root root 28 5月 31 02:24 50-CPUAccounting.conf
4 -rw-r--r-- 1 root root 31 5月 31 02:24 50-MemoryAccounting.conf
$ cat /etc/systemd/system/sshd.service.d/50-CPUAccounting.conf
[Service]
CPUAccounting=yes
$ cat /etc/systemd/system/sshd.service.d/50-MemoryAccounting.conf
[Service]
MemoryAccounting=yes
After configuration is complete, and then restart the sshd
service:
$ systemctl daemon-reload
$ systemctl restart sshd
Then re-run systemd-cgtop command, you can see sshd resource usage statistics:
Open resource usage statistics may increase the load on the system, because the resources have to consume CPU and memory statistics, in most cases the use of
top
command to see enough. Of course, this is the Linux system Well, all the control is in your own hands, you want to do on how to do it.
2. CPU allocation time relative
Through the study of the article we know the CPU shares
can be used to set the relative CPU usage time, then we have to verify it through practice.
The following experiments conducted are carried out on a single-core CPU system, where multi-core single-core is completely different, the end of the text will be discussed separately.
The test object is a service and two ordinary user, where the user tom
's UID is 1000, you can view the following command:
$ cat /etc/passwd|grep tom
tom:x:1000:1000::/home/tom:/bin/bash
Create a foo.service
:
$ cat /etc/systemd/system/foo.service
[Unit]
Description=The foo service that does nothing useful
After=remote-fs.target nss-lookup.target
[Service]
ExecStart=/usr/bin/sha1sum /dev/zero
ExecStop=/bin/kill -WINCH ${MAINPID}
[Install]
WantedBy=multi-user.target
/dev/zero
It is a special device file in linux system, when you read it, it will provide unlimited space characters, so foo.service will continue to consume CPU resources. Now we will foo.service of CPU shares changed 2048
:
$ mkdir /etc/systemd/system/foo.service.d
$ cat << EOF > /etc/systemd/system/foo.service.d/50-CPUShares.conf
[Service]
CPUShares=2048
EOF
由于系统默认的 CPU shares 值为 1024
,所以设置成 2048 后,在 CPU 繁忙的情况下,foo.service
会尽可能获取 system.slice
的所有 CPU 使用时间。
现在通过 systemctl start foo.service
启动 foo 服务,并使用 top
命令查看 CPU 使用情况:
目前没有其他进程在消耗 CPU,所以 foo.service 可以使用几乎 100% 的 CPU。
现在我们让用户 tom
也参与进来,先将 user-1000.slice
的 CPU shares 设置为 256
:
$ systemctl set-property user-1000.slice CPUShares=256
使用用户 tom
登录该系统,然后执行命令 sha1sum /dev/zero
,再次查看 CPU 使用情况:
现在是不是感到有点迷惑了?foo.service 的 CPU shares 是 2048
,而用户 tom 的 CPU shares 只有 256
,难道用户 tom
不是应该只能使用 10% 的 CPU 吗?回忆一下我在上一节提到的,当 CPU 繁忙时,user.slice
和 system.slice
会各获得 50%
的 CPU 使用时间。而这里恰好就是这种场景,同时 user.slice
下面只有 sha1sum 进程比较繁忙,所以会获得 50% 的 CPU 使用时间。
最后让用户 jack
也参与进来,他的 CPU shares 是默认值 1024。使用用户 jack
登录该系统,然后执行命令 sha1sum /dev/zero
,再次查看 CPU 使用情况:
上面我们已经提到,这种场景下 user.slice
和 system.slice
会各获得 50%
的 CPU 使用时间。用户 tom 的 CPU shares 是 256
,而用户 jack 的 CPU shares 是 1024
,因此用户 jack 获得的 CPU 使用时间是用户 tom 的 4
倍。
3. 分配 CPU 绝对使用时间
上篇文章已经提到,如果想严格控制 CPU 资源,设置 CPU 资源的使用上限,即不管 CPU 是否繁忙,对 CPU 资源的使用都不能超过这个上限,可以通过 CPUQuota
参数来设置。下面我们将用户 tom 的 CPUQuota 设置为 5%
:
$ systemctl set-property user-1000.slice CPUQuota=5%
这时你会看到用户 tom 的 sha1sum 进程只能获得 5% 左右的 CPU 使用时间。
如果此时停止 foo.service
,关闭用户 jack 的 sha1sum 进程,你会看到用户 tom 的 sha1sum 进程仍然只能获得 5%
左右的 CPU 使用时间。
如果某个非核心服务很消耗 CPU 资源,你可以通过这种方法来严格限制它对 CPU 资源的使用,防止对系统中其他重要的服务产生影响。
4. 动态设置 cgroup
cgroup 相关的所有操作都是基于内核中的 cgroup virtual filesystem,使用 cgroup 很简单,挂载这个文件系统就可以了。系统默认情况下都是挂载到 /sys/fs/cgroup
目录下,当 service 启动时,会将自己的 cgroup 挂载到这个目录下的子目录。以 foo.service
为例:
先进入 system.slice
的 CPU 子系统:
$ cd /sys/fs/cgroup/cpu,cpuacct/system.slice
查看 foo.service 的 cgroup 目录:
$ ls foo.*
zsh: no matches found: foo.*
因为 foo.service 没有启动,所以没有挂载 cgroup 目录,现在启动 foo.service,再次查看它的 cgroup 目录:
$ ls foo.serice
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
也可以查看它的 PID 和 CPU shares:
$ cat foo.service/tasks
20225
$ cat foo.service/cpu.shares
2048
理论上我们可以在
/sys/fs/cgroup
目录中动态改变 cgroup 的配置,但我不建议你在生产环境中这么做。如果你想通过实验来深入理解 cgroup,可以多折腾折腾这个目录。
5. 如果是多核 CPU 呢?
上面的所有实验都是在单核 CPU 上进行的,下面我们简单讨论一下多核的场景,以 2 个 CPU 为例。
首先来说一下 CPU shares,shares 只能针对单核 CPU 进行设置,也就是说,无论你的 shares 值有多大,该 cgroup 最多只能获得 100% 的 CPU 使用时间(即 1 核 CPU)。还是用本文第 2 节的例子,将 foo.service 的 CPU shares 设置为 2048,启动 foo.service,这时你会看到 foo.service 仅仅获得了 100% 的 CPU 使用时间,并没有完全使用两个 CPU 核:
再使用用户 tom
登录系统,执行命令 sha1sum /dev/zero
,你会发现用户 tom 的 sha1sum 进程和 foo.service 各使用 1 个 CPU 核:
再来说说 CPUQuota,这个上篇文章结尾已经提过了,如要让一个 cgroup 完全使用两个 CPU 核,可以通过 CPUQuota 参数来设置。例如:
$ systemctl set-property foo.service CPUQuota=200%
至于进程最后能不能完全使用两个 CPU 核,就要看它自身的设计支持不支持了。
6. 总结
本文通过具体的示例来观察不同的 cgroup 设置对性能的影响,下面一篇文章将会演示如何通过 cgroup 来限制内存的使用。