cgroup(control groups,控制组群) 是 Linux 内核提供的一个用来限制和控制进程组的资源(CPU、内存、磁盘io等)的功能。cgroup 大家最熟知得场景应该就是容器了,LXC 和 docker 都用 cgroup 和命名空间来控制和限制资源,当然我们也可以直接用它来限制应用程序。 cgroup 为每种可以控制的资源定义了一个子系统:
cgroup 子系统挂载目录查询:
$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup 资源一般都挂载在/sys/fs/cgroup
下面:
$ ll /sys/fs/cgroup
total 0
drwxr-xr-x 4 root root 0 Jun 18 01:40 blkio
lrwxrwxrwx 1 root root 11 Jun 18 01:40 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jun 18 01:40 cpuacct -> cpu,cpuacct
drwxr-xr-x 5 root root 0 Aug 6 11:21 cpu,cpuacct
drwxr-xr-x 3 root root 0 Jun 18 01:40 cpuset
drwxr-xr-x 4 root root 0 Jun 18 01:40 devices
drwxr-xr-x 3 root root 0 Jun 18 01:40 freezer
drwxr-xr-x 3 root root 0 Jun 18 01:40 hugetlb
drwxr-xr-x 5 root root 0 Aug 6 11:21 memory
lrwxrwxrwx 1 root root 16 Jun 18 01:40 net_cls -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Jun 18 01:40 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jun 18 01:40 net_prio -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Jun 18 01:40 perf_event
drwxr-xr-x 4 root root 0 Jun 18 01:40 pids
drwxr-xr-x 4 root root 0 Jun 18 01:40 systemd
要构建这么一个收限制的应用程序,本质就是将应用程序的进程组加入 cgroup 中。
由于 cgroups 是通过 VFS(Virtual File System, 虚拟文件系统)的方式把相关的功能暴露给用户,因此我们可以直接通过对文件的操作来实现 cgroups。
比如我们要创建一个限制 CPU 的 cgroups,名字叫 webtest,我们可以直接用 mkdir 命令进行创建:
mkdir
的创建文件夹的方法因此,我们创建的时候用mkdir -p
直接在 cpu 目录下面创建文件夹即可:
$ mkdir -p /sys/fs/cgroup/cpu/webtest
```
在系统目录下创建文件夹之后, cgroups 程序会某人为一个cgroup,因此会在新生成的文件夹中自动生成相关设置文件,这样要注意的是,cpu 文件夹是指向 cpu,cpuacct:
```bash
$ ll /sys/fs/cgroup/cpu
lrwxrwxrwx 1 root root 11 Jun 21 2019 /sys/fs/cgroup/cpu -> cpu,cpuacct
因此,我们要看到真实目录是要在cpu,cpuacct/
目录下:
$ ll /sys/fs/cgroup/cpu,cpuacct/
total 0
-rw-r--r-- 1 root root 0 Jun 21 2019 cgroup.clone_children
--w--w--w- 1 root root 0 Jun 21 2019 cgroup.event_control
-rw-r--r-- 1 root root 0 Jun 21 2019 cgroup.procs
-r--r--r-- 1 root root 0 Jun 21 2019 cgroup.sane_behavior
-r--r--r-- 1 root root 0 Jun 21 2019 cpuacct.stat
-rw-r--r-- 1 root root 0 Jun 21 2019 cpuacct.usage
-r--r--r-- 1 root root 0 Jun 21 2019 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Jun 21 2019 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jun 21 2019 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jun 21 2019 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Jun 21 2019 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Jun 21 2019 cpu.shares
-r--r--r-- 1 root root 0 Jun 21 2019 cpu.stat
-rw-r--r-- 1 root root 0 Jun 21 2019 notify_on_release
-rw-r--r-- 1 root root 0 Jun 21 2019 release_agent
drwxr-xr-x 58 root root 0 Sep 30 22:03 system.slice
-rw-r--r-- 1 root root 0 Jun 21 2019 tasks
drwxr-xr-x 2 root root 0 Jun 23 2019 user.slice
drwxr-xr-x 2 root root 0 Oct 1 00:12 webtest
除了mkdir
命令,我们也可以用cgcreate
创建。
cgcreate
的创建文件夹的方法除了mkdir
这种直接创建文件目录的方法外,官方提供cgcreate
命令用于创建 cgroups :
$ cgcreate admin:admin -g cpu:website
cgcreate 命令参数:
$ man cgcreate
cgcreate [-h] [-s] [-t <tuid>:<tgid>] [-a <agid>:<auid>] [-f mode] [-d mode] -g <controllers>:<path>
-t <tuid>:<tgid>
定义拥有cgroup的任务文件文件权限用户及用户组,
-a <agid>:<auid>
定义拥有cgroup的其他文件权限用户及用户组,如设置子系统参数和创建subgroups
-d, --dperm mode
文件目录权限
-f, --fperm mode
文件夹权限
-g <controllers>:<path>
子系统和新建文件路径
cgroups 下面每个子系统都有很多参数,其中cpu.cfs_quota_us 是控制CPU 运行时间的,其默认值为100000,我们将其改为 3000,即使用 3% 的CPU:
echo 3000 > /sys/fs/cgroup/cpu/webtest/cpu.cfs_quota_us
我们通过sha1sum /dev/zero
来跑满单颗 CPU。查看应用 PID :
将应用程序 PID 写入 webtest 目录的 tasks 中,我们这次的应用程序PID是22413:
$ echo "22413" > /sys/fs/cgroup/cpu/webtest/tasks
可以看到,CPU 使用率已经由百分之百降到百分之三以内:
经过一段时间的观察,不过有意思的是,程序偶尔有超过 3%,这也是为什么 cgroup 并不是严格的 CPU 分片。
containerd 提供了一个 cgroups 库,用于 cgroups 控制,详见:https://github.com/containerd/cgroups 这里简单介绍下其基本用法:
shares := uint64(100)
control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/test"), &specs.LinuxResources{
CPU: &specs.CPU{
Shares: &shares,
},
})