推荐大家到公众号阅读, 那里阅读体验更好, 也沉淀了很多篇干货.
前面两篇文章我们总结了 Docker 背后使用的资源隔离技术 Linux namespace.
Docker 基础技术之 Linux namespace 详解
Docker 基础技术之 Linux namespace 源码分析
本篇将讨论另外一个技术 -- 资源限额, 这是由 Linux cgroups 来实现的.
cgroups 是 Linux 内核提供的一种机制, 这种机制可以根据需求把一系列任务及子任务整合 (或分隔) 到按资源划分等级的不同组内, 从而为系统资源管理提供一个统一的框架.(来自 Docker 容器与容器云)
通俗来说, cgroups 可以限制和记录任务组 (进程组或线程组) 使用的物理资源(包括 CPU, 内存, IO 等).
为了方便用户 (程序员) 操作, cgroups 以一个伪文件系统的方式实现, 并对外提供 API, 用户对文件系统的操作就是对 cgroups 的操作.
从实现上来, cgroups 实际上是给每个执行任务挂了一个钩子, 当任务执行过程中涉及到对资源的分配使用时, 就会触发钩子上的函数对相应的资源进行检测, 从而对资源进行限制和优先级分配.
cgroups 的作用
总结下来, cgroups 提供以下四个功能:
资源限制: cgroups 可以对任务使用的资源总额进行限制, 如设定应用运行时使用内存的上限, 一旦超过这个配额就发出 OOM(Out of Memory)提示.
优先级分配: 通过分配的 CPU 时间片数量和磁盘 IO 带宽大小, 实际上就相当于控制了任务运行的优先级.
资源统计: cgroups 可以统计系统的资源使用, 如 CPU 使用时长, 内存用量等, 这个功能非常适用于计费.
任务控制: cgroups 可以对任务执行挂起, 恢复等操作.
cgroups 的子系统
cgroups 在设计时根据不同的资源类别分为不同的子系统, 一个子系统本质上是一个资源控制器, 比如 CPU 资源对应 CPU 子系统, 负责控制 CPU 时间片的分配, 内存对应内存子系统, 负责限制内存的使用量. 进一步, 一个子系统或多个子系统可以组成一个 cgroup,cgroups 中的资源控制都是以 cgroup 为单位来实现, 一个任务 (或进程或线程) 可以加入某个 cgroup, 也可以从一个 cgroup 移动到另一个 cgroup, 但这里有一些限制, 在此就不再赘述了, 详细查阅相关资料了解.
对于我们来说, 最关键的是知道怎么用, 下面就针对 CPU, 内存和 IO 资源来看 Docker 是如何使用的?
对于 CPU,Docker 使用参数 -c 或 --cpu-shares 来设置一个容器使用的 CPU 权重, 权重的大小也影响了 CPU 使用的优先级.
如下, 启动两个容器, 并分配不同的 CPU 权重, 最终 CPU 使用率情况:
- docker run --name "container_A" -c 1024 ubuntu
- docker run --name "container_B" -c 512 ubuntu
当只有一个容器时, 即使指定较少的 CPU 权重, 它也会占满整个 CPU, 说明这个权重只是相对权重, 如下将上面的 "container_A" 停止,"container_B" 就分配到全部可用的 CPU.
对于内存, Docker 使用 -m(设置内存的限额)和 --memory-swap(设置内存和 swap 的限额)来控制容器内存的使用量, 如下, 给容器限制 200M 的内存和 100M 的 swap, 然后给容器内的一个工作线程分配 280M 的内存, 因为 280M 在容许的 300M 范围内, 没有问题. 其内存分配过程是不断分配又释放, 如下:
如果让工作线程使用内存超过 300M, 则出现内存超限的错误, 容器退出, 如下:
对于 IO 资源, 其使用方式与 CPU 一样, 使用 --blkio-weight 来设置其使用权重, IO 衡量的两个指标是 bps(byte per second, 每秒读写的数据量) 和 iops(io per second, 每秒 IO 的次数), 实际使用, 一般使用这两个指标来衡量 IO 读写的带宽, 几种使用参数如下:
--device-read-bps, 限制读某个设备的 bps.
--device-write-bps, 限制写某个设备的 bps.
--device-read-iops, 限制读某个设备的 iops.
--device-write-iops, 限制写某个设备的 iops.
假如限制容器对其文件系统 /dev/sda 的 bps 写速率为 30MB/s, 则在容器中用 dd 测试其写磁盘的速率如下, 可见小于 30MB/s.
如果是正常情况下, 我的机器可以达到 56.7MB/s, 一般都是超 1G 的.
上面几个资源使用限制的例子, 本质上都是调用了 Linux kernel 的 cgroups 机制来实现的, 每个容器创建后, Linux 会为每个容器创建一个 cgroup 目录, 以容器的 ID 命名, 目录在 /sys/fs/cgroup/ 中, 针对上面的 CPU 资源限制的例子, 我们可以在 /sys/fs/cgroup/cpu/docker 中看到相关信息, 如下:
其中, cpu.shares 中保存的就是限制的数值, 其他还有很多项, 感兴趣可以动手实验看看.
总结
cgroups 的作用, cgroups 的实现, cgroups 的子系统机制, CPU, 内存和 IO 的使用方式, 以及对应 Linux 的 cgroups 文件目录.
来源: https://www.cnblogs.com/bakari/p/8971602.html