关于程序员:Docker核心技术之Cgroups浅析

8次阅读

共计 5994 个字符,预计需要花费 15 分钟才能阅读完成。

概述

  • [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 的装置

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

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

正文完
 0