概述
-
[1. Cgroups 简介]
- [1.1 性能和定位] - [1.2 相干概念介绍] - [1.3 子系统] - [1.4 cgroups 文件系统]
-
[2. cgroups 子系统]
- [2.1 cpu 子系统] - [2.2 cpuacct 子系统] - [2.3 cpuset 子系统] - [2.4 memory 子系统] - [2.5 blkio 子系统 - block io]
-
[3. cgroups 的装置和应用]
- [3.1 cgroup 的装置] - [3.2 将过程退出到资源限度组]
- [4. 总结]
1. Cgroups 简介
1.1 性能和定位
Cgroups 全称 Control Groups,是 Linux 内核提供的物理资源隔离机制,通过这种机制,能够实现对 Linux 过程或者过程组的资源限度、隔离和统计性能。比方能够通过 cgroup 限度特定过程的资源应用,比方应用特定数目的 cpu 核数和特定大小的内存,如果资源超限的状况下,会被暂停或者杀掉。Cgroup 是于 2.6 内核由 Google 公司主导引入的,它是 Linux 内核实现资源虚拟化的技术基石,LXC(Linux Containers)和 docker 容器所用到的资源隔离技术,正是 Cgroup。
1.2 相干概念介绍
- 工作(task): 在 cgroup 中,工作就是一个过程。
- 控制组(control group): cgroup 的资源管制是以控制组的形式实现,控制组指明了资源的配额限度。过程能够退出到某个控制组,也能够迁徙到另一个控制组。
- 层级(hierarchy): 控制组有层级关系,相似树的构造,子节点的控制组继承父控制组的属性(资源配额、限度等)。
- 子系统(subsystem): 一个子系统其实就是一种资源的控制器,比方 memory 子系统能够管制过程内存的应用。子系统须要退出到某个层级,而后该层级的所有控制组,均受到这个子系统的管制。
概念间的关系:
- 子系统能够附丽多个层级,当且仅当这些层级没有其余的子系统,比方两个层级同时只有一个 cpu 子系统,是能够的。
- 一个层级能够附加多个子系统。
- 一个工作能够是多个 cgroup 的成员,但这些 cgroup 必须位于不同的层级。
- 子过程主动成为父过程 cgroup 的成员,可按需要将子过程移到不同的 cgroup 中。
cgroup 关系图如下:两个工作组成了一个 Task Group,并应用了 CPU 和 Memory 两个子系统的 cgroup,用于管制 CPU 和 MEM 的资源隔离。
1.3 子系统
- cpu: 限度过程的 cpu 使用率。
- cpuacct 子系统,能够统计 cgroups 中的过程的 cpu 应用报告。
- cpuset: 为 cgroups 中的过程调配独自的 cpu 节点或者内存节点。
- memory: 限度过程的 memory 使用量。
- blkio: 限度过程的块设施 io。
- devices: 管制过程可能拜访某些设施。
- net_cls: 标记 cgroups 中过程的网络数据包,而后能够应用 tc 模块(traffic control)对数据包进行管制。
- net_prio: 限度过程网络流量的优先级。
- huge_tlb: 限度 HugeTLB 的应用。
- freezer: 挂起或者复原 cgroups 中的过程。
- ns: 管制 cgroups 中的过程应用不同的 namespace。
1.4 cgroups 文件系统
Linux 通过文件的形式,将 cgroups 的性能和配置裸露给用户,这得益于 Linux 的虚构文件系统(VFS)。VFS 将具体文件系统的细节暗藏起来,给用户态提供一个对立的文件系统 API 接口,cgroups 和 VFS 之间的链接局部,称之为 cgroups 文件系统。比方挂在 cpu、cpuset、memory 三个子系统到 /cgroups/cpu_mem 目录下
mount -t cgroup -o cpu,cpuset,memory cpu_mem /cgroups/cpu_mem
对于虚构文件系统机制,见浅谈 Linux 虚构文件系统机制
2. cgroups 子系统
这里简略介绍几个常见子系统的概念和用法,包含 cpu、cpuacct、cpuset、memory、blkio。
2.1 cpu 子系统
cpu 子系统限度对 CPU 的拜访,每个参数独立存在于 cgroups 虚构文件系统的伪文件中,参数解释如下:
- cpu.shares: cgroup 对工夫的调配。比方 cgroup A 设置的是 1,cgroup B 设置的是 2,那么 B 中的工作获取 cpu 的工夫,是 A 中工作的 2 倍。
- cpu.cfs_period_us: 齐全偏心调度器的调整工夫配额的周期。
- cpu.cfs_quota_us: 齐全偏心调度器的周期当中能够占用的工夫。
-
cpu.stat 统计值
- nr_periods 进入周期的次数
- nr_throttled 运行工夫被调整的次数
- throttled_time 用于调整的工夫
2.2 cpuacct 子系统
子系统生成 cgroup 工作所应用的 CPU 资源报告,不做资源限度性能。
- cpuacct.usage: 该 cgroup 中所有工作总共应用的 CPU 工夫(ns 纳秒)
- cpuacct.stat: 该 cgroup 中所有工作总共应用的 CPU 工夫,辨别 user 和 system 工夫。
- cpuacct.usage_percpu: 该 cgroup 中所有工作应用各个 CPU 核数的工夫。
通过 cpuacct 如何计算 CPU 利用率呢?能够通过 cpuacct.usage
来计算整体的 CPU 利用率,计算如下:
# 1. 获取以后工夫(纳秒)tstart=$(date +%s%N)
# 2. 获取 cpuacct.usage
cstart=$(cat /xxx/cpuacct.usage)
# 3. 距离 5s 统计一下
sleep 5
# 4. 再次采点
tstop=$(date +%s%N)
cstop=$(cat /xxx/cpuacct.usage)
# 5. 计算利用率
($cstop - $cstart) / ($tstop - $tstart) * 100
2.3 cpuset 子系统
实用于调配独立的 CPU 节点和 Mem 节点,比方将过程绑定在指定的 CPU 或者内存节点上运行,各参数解释如下:
- cpuset.cpus: 能够应用的 cpu 节点
- cpuset.mems: 能够应用的 mem 节点
- cpuset.memory_migrate: 内存节点扭转是否要迁徙?
- cpuset.cpu_exclusive: 此 cgroup 里的工作是否独享 cpu?
- cpuset.mem_exclusive:此 cgroup 里的工作是否独享 mem 节点?
- cpuset.mem_hardwall: 限度内核内存调配的节点(mems 是用户态的调配)
- cpuset.memory_pressure: 计算换页的压力。
- cpuset.memory_spread_page: 将 page cache 调配到各个节点中,而不是以后内存节点。
- cpuset.memory_spread_slab: 将 slab 对象 (inode 和 dentry) 扩散到节点中。
- cpuset.sched_load_balance: 关上 cpu set 中的 cpu 的负载平衡。
- cpuset.sched_relax_domain_level: the searching range when migrating tasks
- cpuset.memory_pressure_enabled: 是否须要计算 memory_pressure?
2.4 memory 子系统
memory 子系统次要波及内存一些的限度和操作,次要有以下参数:
- memory.usage_in_bytes # 以后内存中的使用量
- memory.memsw.usage_in_bytes # 以后内存和替换空间中的使用量
- memory.limit_in_bytes # 设置 or 查看内存使用量
- memory.memsw.limit_in_bytes # 设置 or 查看 内存加替换空间使用量
- memory.failcnt # 查看内存使用量被限度的次数
- memory.memsw.failcnt # – 查看内存和替换空间使用量被限度的次数
- memory.max_usage_in_bytes # 查看内存最大使用量
- memory.memsw.max_usage_in_bytes # 查看最大内存和替换空间使用量
- memory.soft_limit_in_bytes # 设置 or 查看内存的 soft limit
- memory.stat # 统计信息
- memory.use_hierarchy # 设置 or 查看层级统计的性能
- memory.force_empty # 触发强制 page 回收
- memory.pressure_level # 设置内存压力告诉
- memory.swappiness # 设置 or 查看 vmscan swappiness 参数
- memory.move_charge_at_immigrate # 设置 or 查看 controls of moving charges?
- memory.oom_control # 设置 or 查看内存超限管制信息(OOM killer)
- memory.numa_stat # 每个 numa 节点的内存应用数量
- memory.kmem.limit_in_bytes # 设置 or 查看 内核内存限度的硬限
- memory.kmem.usage_in_bytes # 读取以后内核内存的调配
- memory.kmem.failcnt # 读取以后内核内存调配受限的次数
- memory.kmem.max_usage_in_bytes # 读取最大内核内存使用量
- memory.kmem.tcp.limit_in_bytes # 设置 tcp 缓存内存的 hard limit
- memory.kmem.tcp.usage_in_bytes # 读取 tcp 缓存内存的使用量
- memory.kmem.tcp.failcnt # tcp 缓存内存调配的受限次数
- memory.kmem.tcp.max_usage_in_bytes # tcp 缓存内存的最大使用量
2.5 blkio 子系统 – block io
次要用于管制设施 IO 的拜访。有两种限度形式:权重和下限,权重是给不同的利用一个权重值,按百分比应用 IO 资源,下限是管制利用读写速率的最大值。按权重调配 IO 资源:
- blkio.weight:填写 100-1000 的一个整数值,作为绝对权重比率,作为通用的设施调配比。
- blkio.weight_device:针对特定设施的权重比,写入格局为
device_types:node_numbers weight
,空格前的参数段指定设施,weight 参数与 blkio.weight 雷同并笼罩原有的通用调配比。
按下限限度读写速度:
- blkio.throttle.read_bps_device:按每秒读取块设施的数据量设定下限,格局 device_types:node_numbers bytes_per_second。
- blkio.throttle.write_bps_device:按每秒写入块设施的数据量设定下限,格局 device_types:node_numbers bytes_per_second。
- blkio.throttle.read_iops_device:按每秒读操作次数设定下限,格局 device_types:node_numbers operations_per_second。
- blkio.throttle.write_iops_device:按每秒写操作次数设定下限,格局 device_types:node_numbers operations_per_second
针对特定操作 (read, write, sync, 或 async) 设定读写速度下限
- blkio.throttle.io_serviced:针对特定操作按每秒操作次数设定下限,格局 device_types:node_numbers operation operations_per_second
- blkio.throttle.io_service_bytes:针对特定操作按每秒数据量设定下限,格局 device_types:node_numbers operation bytes_per_second
3. cgroups 的装置和应用
测试环境为 ubuntu 18.10
3.1 cgroups 的装置
- 装置 cgroups
sudo apt install cgroup-bin
装置实现后,零碎会呈现该目录/sys/fs/cgroup
。
- 创立 cpu 资源控制组,限度 cpu 使用率最大为 50%
$ cd /sys/fs/cgroup/cpu
$ sudo mkdir test_cpu
$ sudo echo '10000' > test_cpu/cpu.cfs_period_us
$ sudo echo '5000' > test_cpu/cpu.cfs_quota_us
- 创立 mem 资源控制组,限度内存最大应用为 100MB
$ cd /sys/fs/cgroup/memory
$ sudo mkdir test_mem
$ sudo echo '104857600' > test_mem/memory.limit_in_bytes
3.2 将过程退出到资源限度组
测试代码 test.cc
如下:
#include <unistd.h>
#include <stdio.h>
#include <cstring>
#include <thread>
void test_cpu() {printf("thread: test_cpu start\n");
int total = 0;
while (1) {++total;}
}
void test_mem() {printf("thread: test_mem start\n");
int step = 20;
int size = 10 * 1024 * 1024; // 10Mb
for (int i = 0; i < step; ++i) {char* tmp = new char[size];
memset(tmp, i, size);
sleep(1);
}
printf("thread: test_mem done\n");
}
int main(int argc, char** argv) {std::thread t1(test_cpu);
std::thread t2(test_mem);
t1.join();
t2.join();
return 0;
}
1. 编译该程序
g++ -o test test.cc --std=c++11 -lpthread
2. 察看限度之前的运行状态3. 测试 cpu 的限度
cgexec -g cpu:test_cpu ./test
cpu 使用率升高了一半。除了应用 cgexec 限度过程外,还能够通过将过程号退出到 cgroup.procs 的形式,来达到限度目标。
4. 总结
本文简略介绍了 Cgroups 的概念和应用,通过 Cgroups 能够实现资源限度和隔离。在理论的生产环境中,Cgroups 技术被大量利用在各种容器技术中,包含 docker、rocket 等。这种资源限度和隔离技术的呈现,使得模块间互相混部成为可能,大大提高了机器资源利用率,这也是云计算的关键技术之一。
原文连贯