Shawn摘要
k8s 官方对cgropu v2
的介绍
https://kubernetes.io/docs/concepts/architecture/cgroups/
cgroup v2 is the next version of the Linux cgroup
API. cgroup v2 provides a unified control system with enhanced resource management capabilities. cgroup v2 是 Linux cgroup
API 的下一个版本。 cgroup v2提供了统一的控制系统,增强了资源管理能力。
cgroup v2 offers several improvements over cgroup v1, such as the following: cgroup v2 相对于 cgroup v1 进行了多项改进,例如:
Single unified hierarchy design in API API中单一统一的层次结构设计
Safer sub-tree delegation to containers 更安全的子树委托给容器
Newer features like Pressure Stall Information 压力失速信息 等新功能
Enhanced resource allocation management and isolation across multiple resources
增强的资源分配管理和跨多个资源的隔离
Unified accounting for different types of memory allocations (network memory, kernel memory, etc) 统一核算不同类型的内存分配(网络内存、内核内存等)
Accounting for non-immediate resource changes such as page cache write backs 考虑非立即资源更改,例如页面缓存写回
查看当前 linux 上的 cgroup
版本 1 stat -fc %T /sys/fs/cgroup/
如果是 cgroup v2
会输出 cgroup2fs
如果是 cgropu v1
会输出 tmpfs
Linux Cgroups Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。
在Linux中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup
路径下。
可以看到,在/sys/fs/cgroup
下面有很多诸如cpuset,cpu,memory
这样的子目录,也叫子系统。这些都是我这台机器当前可以被cgroups
进行限制的资源种类,在最新的cgroup v2,则是在一个目录下统一了进行限制的资源种类。而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法。比如,对CPU子系统来说,我们就可以看到如下几个配置文件
1 2 3 $ ls /sys/fs/cgroup/cpu cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
而这样的配置文件又如何使用呢?
cgroup v2
可以直接在 cgroup
目录下创建一个目录,这个目录就称为一个“控制组”。操作系统会在新创建的 container
目录下,自动生成该子系统对应的资源文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 mkdir containerls /sys/fs/cgroup/container cgroup.controllers cgroup.type cpu.stat hugetlb.1GB.rsvd.max io.stat memory.oom.group pids.events cgroup.events cpu.idle cpu.uclamp.max hugetlb.2MB.current io.weight memory.pressure pids.max cgroup.freeze cpu.max cpu.uclamp.min hugetlb.2MB.events memory.current memory.stat rdma.current cgroup.kill cpu.max.burst cpu.weight hugetlb.2MB.events.local memory.events memory.swap.current rdma.max cgroup.max.depth cpu.pressure cpu.weight.nice hugetlb.2MB.max memory.events.local memory.swap.events cgroup.max.descendants cpuset.cpus hugetlb.1GB.current hugetlb.2MB.rsvd.current memory.high memory.swap.high cgroup.procs cpuset.cpus.effective hugetlb.1GB.events hugetlb.2MB.rsvd.max memory.low memory.swap.max cgroup.stat cpuset.cpus.partition hugetlb.1GB.events.local io.max memory.max misc.current cgroup.subtree_control cpuset.mems hugetlb.1GB.max io.pressure memory.min misc.max cgroup.threads cpuset.mems.effective hugetlb.1GB.rsvd.current io.prio.class memory.numa_stat pids.current
如果在后台执行一条脚本
1 2 while : ; do : ; done & [1] 1242421
这样执行一个死循环,可以把CPU吃到100%,根据他的输出,我们可以看到这个脚本在后台运行的进程号(PID)是1242421。
可以用top命令来确认一下CPU有没有被打满
1 2 3 4 5 6 7 8 9 10 11 12 13 top - 20:17:13 up 43 days, 6:30, 2 users , load average: 0.45, 0.14, 0.04 Tasks: 257 total, 2 running, 251 sleeping, 0 stopped, 4 zombie %Cpu(s): 0.2 us, 5.2 sy, 7.5 ni, 86.9 id , 0.0 wa, 0.0 hi, 0.1 si, 0.0 st MiB Mem : 16008.0 total, 9279.5 free, 3315.9 used, 3781.0 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 12692.1 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1242421 root 25 5 15512 5264 1312 R 100.0 0.0 0:33.12 zsh 15 root 20 0 0 0 0 I 0.3 0.0 44:17.15 rcu_sched 809 root 20 0 1678752 35040 12208 S 0.3 0.2 77:33.25 proxima 995 root 20 0 261668 28240 14188 S 0.3 0.2 11:09.49 tuned 1885 root 20 0 715824 17920 2496 S 0.3 0.1 145:15.07 modd 2501 root 20 0 1946508 137220 58716 S 0.3 0.8 96:08.09 prometheus
而此时,我们可以通过查看container 目录下的文件,看到 container 控制组里的CPU还没有任何限制
接下来,我们可以通过修改这些文件来设置限制
1 echo "50000 100000" > cpu.max
接下来,我们把被限制的进程的PID写入 container 组里的文件,上面的设置就会对该进程生效了。
1 echo 1242421 > /sys/fs/cgroup/container/cgroup.procs
我们可以用top命令查看一下
1 2 3 4 5 6 7 8 9 10 11 12 top - 20:21:57 up 43 days, 6:35, 2 users , load average: 0.99, 0.79, 0.35 Tasks: 256 total, 2 running, 250 sleeping, 0 stopped, 4 zombie %Cpu(s): 0.2 us, 3.1 sy, 3.4 ni, 93.2 id , 0.0 wa, 0.0 hi, 0.0 si, 0.0 st MiB Mem : 16008.0 total, 9277.7 free, 3317.5 used, 3781.2 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 12690.5 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1242421 root 25 5 15512 5460 1508 R 50.0 0.0 5:11.03 zsh 5138 root 20 0 763316 57960 32964 S 0.7 0.4 101:21.99 travel-rpc 8900 root 20 0 7963760 1.0g 24972 S 0.7 6.4 322:17.96 java 809 root 20 0 1678752 34716 12208 S 0.3 0.2 77:33.60 proxima 2251 root 20 0 1521496 171928 111160 S 0.3 1.0 50:19.36 grafana
除CPU子系统外,Cgroups的每一个子系统都有其独有的资源限制能力,比如:
blkio,为块设备设定I/O限制,一般用于磁盘等设备;
cpuset,为进程分配单独的CPU核和对应的内存节点
memory,为进程设定内存使用的限制。
cgroup v1和cgropu v2的区别是什么? 目录结构区别 cgroup v2 1 2 3 4 5 6 7 8 ls cgroup.controllers cgroup.threads dev-hugepages.mount io.prio.class proc-sys-fs-binfmt_misc.mount user.slice cgroup.max.depth container dev-mqueue.mount io.stat sys-fs-fuse-connections.mount cgroup.max.descendants cpu.pressure init.scope memory.numa_stat sys-kernel-config.mount cgroup.procs cpuset.cpus.effective io.cost.model memory.pressure sys-kernel-debug.mount cgroup.stat cpuset.mems.effective io.cost.qos memory.stat sys-kernel-tracing.mount cgroup.subtree_control cpu.stat io.pressure misc.capacity system.slice
cgroup v1 1 2 3 $ ls /sys/fs/cgroup/cpu cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
cgroup v1
下cpu,memory...
每个资源都有一个单独的目录,而cgroup v2
则是创建一个单独的目录,将所有的资源(cpu,memory)都集中在一起。
1 2 3 4 root@ubuntu:/sys/fs/cgroup/cpu$ mkdir container root@ubuntu:/sys/fs/cgroup/cpu$ ls container/ cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
配置文件名的区别 cgroup v2 进入到新创建的 container 目录
1 2 3 4 5 6 7 8 9 10 11 cgroup.controllers cgroup.type cpu.stat hugetlb.1GB.rsvd.max io.stat memory.oom.group pids.events cgroup.events cpu.idle cpu.uclamp.max hugetlb.2MB.current io.weight memory.pressure pids.max cgroup.freeze cpu.max cpu.uclamp.min hugetlb.2MB.events memory.current memory.stat rdma.current cgroup.kill cpu.max.burst cpu.weight hugetlb.2MB.events.local memory.events memory.swap.current rdma.max cgroup.max.depth cpu.pressure cpu.weight.nice hugetlb.2MB.max memory.events.local memory.swap.events cgroup.max.descendants cpuset.cpus hugetlb.1GB.current hugetlb.2MB.rsvd.current memory.high memory.swap.high cgroup.procs cpuset.cpus.effective hugetlb.1GB.events hugetlb.2MB.rsvd.max memory.low memory.swap.max cgroup.stat cpuset.cpus.partition hugetlb.1GB.events.local io.max memory.max misc.current cgroup.subtree_control cpuset.mems hugetlb.1GB.max io.pressure memory.min misc.max cgroup.threads cpuset.mems.effective hugetlb.1GB.rsvd.current io.prio.class memory.numa_stat pids.current
cpu.max
:用于限制 CPU 使用。
查看当前 CPU 限制 :
1 cat /sys/fs/cgroup/cpu.max
如果结果是 max 100000
,表示没有限制。
设置 CPU 限制 :
例如,要限制某个 cgroup 使用不超过 50% 的 CPU:
1 echo "50000 100000" > /sys/fs/cgroup/cpu.max
这表示在每 100ms 的周期内,最多使用 50ms 的 CPU 时间。
cgroup v1 cfs_period
和cfs_quota
这两个参数需要组合使用,可以用来限制进程在长度为cfs_period
的一段时间内,只能被分配到总量为cfs_quota
的CPU时间
1 2 3 4 $ cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us -1 $ cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us 100000
通过查看container目录下的文件,看到container控制组里的CPU quota
还没有任何限制(即-1),CPU period
则是默认的100ms(100000 us)
把被限制的进程的PID写入container组里的tasks
文件,上面的设置就会对该进程生效了
1 $ echo 226 > /sys/fs/cgroup/cpu/container/tasks
在 cgroup v2 中,tasks
文件已被移除,使用的是 cgroup.procs
文件来管理进程。以下是如何在 cgroup v2 中操作的步骤:
创建 cgroup :
1 mkdir /sys/fs/cgroup/unified/my_cgroup
将进程加入 cgroup :
1 echo 226 > /sys/fs/cgroup/unified/my_cgroup/cgroup.procs