前言
本文主要会介绍笔者在学习Linux Cgroups CPU Subsystem时所总结的知识点,其中会涉及到Linux CPU进程时间使用、CPU Subsystem的配置参数以及CPU资源监控数据
等方面的相关内容。
笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也是很重要的学习过程之一。
1.CPU时间使用类型
对于CPU这样的计算资源,Linux Cgroups是将进程使用CPU的时长最为基础单位来进行资源限制管控的基本单位的。因此了解Linux中的进程CPU时间使用类型会有助于更好的使用Linux Cgroups CPU Subsystem来管控CPU资源。
如果按照Linux 内的进程状态来分类,则CPU时间使用类型可分为两大类:
- 用户态 ni: Nice,即低优先级的用户态进程的CPU使用时长。 us: User,即用户态进程的CPU使用时长,但不包括ni。
- 内核态 sys: System, 即内核态进程的CPU使用时长。 id: Idle, 即CPU空闲时间,即无任何进程运行的时长。 wa: IOwait, 即系统等待I/O的CPU使用时长。 hi: Hardware irq, 即处理硬中断的CPU使用时长。 si: Soft irq, 即处理软中断的CPU使用时长。 st: Steal, 即同一宿主机上的vm的CPU使用时长。
2.CPU Subsystem
CPU Subsystem 是Linux Cgroups其中的一个,其负责限制进程对于CPU类资源的使用。
2.1 实现方式
每个Subsystem都是通过一个虚拟文件系统挂载点的方式,挂到一个缺省的目录下。
Tips: 实现原理可以阅读笔者另一遍介绍Linux Cgroups原理的文章
CPU Subsystem一般在 Linux 发行版里会放在 /sys/fs/cgroup/cpu 这个目录下。其次,CPU Subsystem中还会包含多个控制组Control Group;同理,每一个Control Group会在cpu/子目录下建立相应的目录
。同时,每一个Control Group还可以包含着其他的Control Group,即Control Group之间的关系是一种树型结构关系。
注意: 这里基于Linux Cgroups V1版本来进行讲解的。
2.2 配置参数
这里介绍几个重要的配置参数。由于Subsystem是绑定在Control Group上,因此每一个Control Group中都会包含如下配置:
参数名 | 参数说明 |
---|---|
cpu.cfs_period_us | CFS 算法的一个调度周期(毫秒为单位) |
cpu.cfs_quota_us | 表示 CFS 算法中,在一个调度周期里这个控制组被允许的运行时间(毫秒为单位) |
cpu.shares | CPU Cgroup 对于控制组之间的 CPU 分配比例;缺省值为1024 |
cpu.rt_period_us | 设定周期时间。 |
cpu.rt_runtime_us | 设定周期中的运行时间。 |
cpu.stat | 统计信息。其中包含nr_periods(表示经历了几个cfs_period_us周期)、nr_throttled(表示 task 被限制的次数)及throttled_time(表示 task 被限制的总时长) |
cgroup.procs | 里边记录有属于该组进程的pid |
cpuacct.stat | 这里包含了两个统计值,这两个值分别是这个控制组里所有进程的内核态 ticks 和用户态的 ticks |
2.3 控制策略
CPU 资源控制有两种策略:
-
完全公平调度策略(CFS:Completely Fair Scheduler) CFS提供了限额和按比例分配两种方式进行资源控制。CFS算法是Linux中对于普通调度类型进程的调度方法。
-
实时调度策略(Real-Time Scheduler) 针对实时进程按周期分配固定的运行时间。配置时间都以微秒(µs)为单位,文件名中用us表示。
2.3.1 CFS
CFS在不同的场景下会有不同的限制管理方法。
2.3.1.1 CPU资源充足情况
一个Control Group被允许使用的CPU最大配额 = 一个调度周期里这个Control Group被允许的运行时间 / 一个调度周期,即:
每个Control Group中所有进程的可使用CPU资源的最大值 = cpu.cfs_quota_us / cpu.cfs_period_us
2.3.1.2 CPU资源消耗殆尽情况
在现实情况中,往往会有多个进程在抢占cpu资源。这些进程都会从属于在不同的Control Group中,此时就会涉及到不同的Control Group之间对于cpu资源的竞争。
而cpu.shares就是为了解决该问题而存在的。通过配置cpu.shares,可以设定每组能够占用cpu资源的比例。
即cpu.shares 这个值决定了CPU Subsystem下Control Group可用 CPU 的相对比例
。
注意: 只有当系统上CPU资源完全被占满的时候,这个比例才会在各个Control Group间起作用。
实际上设置cpu.shares就是在为进程配置其使用CPU的优先级
。即哪个进程的cpu.shares设置的大,它所占有CPU资源的比例就大,因此该进程就有更高的CPU优先使用权。也可以将其理解是在配置进程对于CPU使用的权重大小。
3.CPU资源报告
CPUACCT Subsystem其内部提供了CPU资源用量的统计
,时间单位都是纳秒。
Tips: CPUACCT Subsystem可以看作是CPU Subsystem的补充。
其中包括的参数:
-
cpuacct.usage 统计 cgroup 中所有 task 的 cpu 使用时长。
-
cpuacct.stat 统计 cgroup 中所有 task 的用户态和内核态分别使用 cpu 的时长。
-
cpuacct.usage_percpu 统计 cgroup 中所有 task 使用每个 cpu 的时长。
4.CPU绑定
如果某些进程需要在指定的相关CPU上运行,此时可以使用CPUSET Subsystem来实现。CPUSET Subsystem能够为进程分配独立的CPU资源
。
其中包括的参数:
-
cpuset.cpus 在这个文件中填写 cgroup 可使用的 CPU 编号,如0-2,16代表 0、1、2 和 16 这 4 个 CPU。
-
cpuset.mems 与 CPU 类似,表示 cgroup 可使用的memory node,格式cpuset.cpus。
Tips: 上述两个参数实际上就是Docker实现CPU绑定的实现原理。