概述

  • [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.usagecstart=$(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的装置

  1. 装置 cgroups
sudo apt install cgroup-bin

装置实现后,零碎会呈现该目录/sys/fs/cgroup

  1. 创立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
  1. 创立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等。这种资源限度和隔离技术的呈现,使得模块间互相混部成为可能,大大提高了机器资源利用率,这也是云计算的关键技术之一。
原文连贯

更多深度文章,关注:二进制社区