Docker 的资源限制与 cgroups
· 4 min read
cgroups
cgroups 原来叫 Process Container 但因为叫 Container 有诸多的歧义,所以干脆就改叫 Control Groups 也就是 cgroups。cgroups 在 2016 年发布了 v2 版本,但本文只讨论 v1 版本的 cgroups,后续将会另外讨论 v2 版本。
定义
- task 任务,通常指的是进程
- subsystem 资源控制器,共有 12 个 subsystem,分别实现对CPU、内存、IO、网络等资源的管控
- cgroup 将多个 task 与多个 subsystem 关联的 Control Group
- hierarchy 层级树,多个 task 以树状结构组成
当前已有的 subsystem 分别是:blkio、cpu,cpuacct、cpuset、devices、freezer、hugetlb、memory、net_cls,net_prio、perf_event、pids、rdma、systemd
cgroup 提供了一个虚拟文件系统作为用户管理 cgroup 的接口,当前环境挂载到了 /sys/fs/cgroup 下
内存控制
根据 docker run --help
获取容器在运行时可以指定的若干个参数如下
--kernel-memory string Kernel memory limit
-m, --memory string Memory limit
--memory-reservation string Memory soft limit
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
--oom-kill-disable Disable OOM Killer
--oom-score-adj int Tune host's OOM preferences (-1000 to 1000)
Memory Limit
Docker 参数 | cgroup interface | 说明 |
---|---|---|
-m, —memory | memory.limit_in_bytes | 内存使用量硬限制 |
—memory-reservation | memory.soft_limit_in_bytes | 内存使用量软限制 |
—oom-kill-disable | memory.oom_control | OOM 策略控制 |
—kernel-memory | memory.kmem.limit_in_bytes | 内核内存使用限制 |
让我们来看看 memory.limit_in_bytes
下面存了什么好东西
root@HYPX-Amoy:/sys/fs/cgroup/memory/playgound# cat memory.limit_in_bytes
268435456
诶,原来就只是一串数字而已,这个值是以 bytes 为单位显示的 256M,它限制了这个 cgroup 下所有的进程使用的总内存只能在 256M 内。memory.soft_limit_in_bytes
下面存的也是类似这样的一个数值,不过应该小于或者等于 memory.limit_in_bytes
。Soft limit 应该比 hard limit 要低,在宿主机内存压力大的时候内核将会尽量的将有配置 soft limit 的 cgroup 下的 task 所用的内存压到 soft limit 值以下(这是一个 best-effort 特性),让其他 cgroup 有机会获得内存。
再看看 memory.oom_control
下面有什么,这个像是个策略控制器
root@HYPX-Amoy:/sys/fs/cgroup/memory/playgound# cat memory.oom_control
oom_kill_disable 0
under_oom 0
这次不只是一个数字了,这还有 KV 来着。oom_kill_disable
有两个值,0(默认) -> OOM 的时候会 kill 掉进程,1 -> OOM 的时候会暂停进程。under_oom
代表了当前 cgroup 是否处于 OOM 状态,由 0 和 1 表示 true 跟 false。
--oom-kill-disable
参数将 memory.oom_control
中的 oom_kill_disable
修改为 1(即 OOM 的之后不会 kill 进程)
Memory Swap
Docker 参数 | cgroup interface | 说明 |
---|---|---|
—memory-swap | memory.memsw.limit_in_bytes | swap 分区限制量 |
—memory-swappiness | memory.swappiness | swap 分区使用倾向比例(姑且这么叫) |
--memory-swap
限制了内存和交换区的使用量总和,实际可用的 swap = memsw.limit_in_bytes - memory.limit_in_bytes
swappiness 取值范围是 0 ~ 100(默认 60),如果为 0 则只会在内存使用完后才使用 swap,否则就会按照给定的比例来适时的使用 swap 分区(具体怎么用,还需要再深入)
root@HYPX-Amoy:/sys/fs/cgroup/memory/kubepods/podaf0d8d80-0bc3-11e8-869d-c81f66d06721# cat memory.swappiness
60
CPU 控制
--cpu-count int CPU count (Windows only)
--cpu-percent int CPU percent (Windows only)
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period int Limit CPU real-time period in microseconds
--cpu-rt-runtime int Limit CPU real-time runtime in microseconds
-c, --cpu-shares int CPU shares (relative weight)
--cpus decimal Number of CPUs
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
其中前两个是 Windows 系统专有参数,在此不做研究。
--cpu-shares
可以理解为是 CPU 抢占时的分配权重。假定当前有两个进程在同一个 cgroups 组下,A task 的 CPU share 是 50 而 B task 的是 25,当同时对于 CPU 资源争抢时,A 可以得到两倍于 B 的资源。在资源空闲期间,A 或者 B 都可以获得所有 CPU 资源。
root@HYPX-Amoy:/sys/fs/cgroup/cpu/kubepods/pod0bb631a0-f373-11e7-8cf2-c81f66d06721# cat cpu.shares
1048
--cpu-period
和 --cpu-quota
需要配合一起食用,使用 CFS Scheduling(完全公平调度)。前者设定了 CFS 调度的时间周期(默认值 100000,单位 微秒),后者定义了当前所在 cgroups 下属 task 可以使用的周期内的时间片(默认 -1 即不限制,单位微秒)
root@HYPX-Amoy:/sys/fs/cgroup/cpu/kubepods/pod0bb631a0-f373-11e7-8cf2-c81f66d06721# cat cpu.cfs_period_us
100000
root@HYPX-Amoy:/sys/fs/cgroup/cpu/kubepods/pod0bb631a0-f373-11e7-8cf2-c81f66d06721# cat cpu.cfs_quota_us
102400
以上示例的值 quota 超出了 period(前者是后者 1.024 倍),意味着在多核心的情况下,该 cgroup 组可以用掉 1.024 核心
--cpu-rt-period
和 --cpu-rt-runtime
同样需要配合在一起,使用的是 Real-Time Scheduling。二者的定义与 CFS 中的 period 和 quota 差不多。[备注:还需要深入看下差异]
--cpus
在 Docker 1.3 后加入的参数,其本质是 --cpu-period
和 --cpu-quota
,例如 --cpus=3
那么等同于 --cpu-period=100000 --cpu-quota=150000
--cpuset-cpus
绑定了容器可以运行的 CPU 节点(并不排斥其他容器也用同样的 CPU 节点),支持 0-3
(0 至 3,共 4 节点)和 0,1
(0 和 1 核心,共 2 节点)的写法。默认所有节点
root@HYPX-Amoy:/sys/fs/cgroup/cpuset/kubepods/pod0bb631a0-f373-11e7-8cf2-c81f66d06721# cat cpuset.cpus
0-7
--cpuset-mems
尽在 NUMA 架构的 CPU 上生效,绑定 CPU 的内存节点。(性能有坑,慎重!NUMA 架构的 CPU — 你真的用好了么?)
root@HYPX-Amoy:/sys/fs/cgroup/cpuset/kubepods/pod0bb631a0-f373-11e7-8cf2-c81f66d06721# cat cpuset.mems
0-1