8. Docker的资源限制

2021-02-10  本文已影响0人  随便写写咯

1 Docker的资源限制

1.1 Docker的资源限制

1.1.1 Docker资源限制介绍

默认情况下, 容器没有资源的使用限制, 可以使用宿主机内核调度程序允许的尽可能多的资源
Docker提供了控制容器使用资源的方法, 可以限制容器使用多少内存或CPU等, 在docker run命令运行时配置标志实现资源限制功能
其中许多功能都要求宿主机的内核支持, 要检查是否支持这些功能, 可以使用docker info命令
如果内核中禁用了某项功能可能会在输出结尾处看到警告, 如下所示
WARNING: No swap limit support
root@Ubuntu-1804-3:~# vim /etc/default/grub
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1 net.ifnames=0"
root@Ubuntu-1804-3:~# update-grub
root@Ubuntu-1804-3:~# reboot

1.1.2 OOM

产生OOM异常时, dockerd会尝试通过调用docker守护进程上的OOM优先级来减轻这些风险, 以便它比系统上的其他进程更不可能被杀死
但是容器的OOM优先级未作调整的话, 会使得单个容器被杀死的可能性比docker守护程序或其他进程杀死的可能性更大, 不推荐通过在守护程序或容器上手动设置--oom -score-adj为极端负数
可以在容器上设置-m限制容器使用的最大物理内存, 然后通过容器上设置--oom-kill-disable来绕过这些安全措施, 当内存不足时, 不kill本容器的进程

OOM优先级机制

Linux会为每个进程计算一个分数, 最终将分数最高的杀掉
/proc/PID/oom_score_adj
范围为 -1000 到 1000, 值越高越容器被宿主机杀掉, 如果将该值设为-1000, 那么该进程永远不会被宿主机内核杀掉
以sshd进程为例, sshd提供远程访问宿主机的功能, 如果随意被杀死那么就无法连接到宿主机, 所以sshd的分数被设定为-1000, 永远不会被杀死
root@Ubuntu-1804-3:~# cat /proc/891/oom_score_adj 
-1000
/proc/PID/oom_adj
范围是 -17 到 +15, 取值越高越容易被kill, 如果是 -17 表示不能被kill, 该设置参数的存在是为了和旧版本的Linux内核兼容
sshd的范围是-17, 永远不会被kill掉
root@Ubuntu-1804-3:~# cat /proc/891/oom_adj 
-17
/proc/PID/oom_score
这个值是系统综合进程的内存消耗量, CPU时间,(uptime+存活时间(uptime-start time))和oom_adj计算出来的进程得分, 消耗内存越多得分越高, 容易被宿主机内核强制杀死
以sshd为例
root@Ubuntu-1804-3:~# cat /proc/891/oom_score
0
dockerd的OOM得分
root@Ubuntu-1804-3:~# pidof dockerd
957
root@Ubuntu-1804-3:~# cat /proc/957/oom_adj 
-8
root@Ubuntu-1804-3:~# cat /proc/957/oom_score
0
root@Ubuntu-1804-3:~# cat /proc/957/oom_score_adj
-500

2 Docker的内存限制

Docker可以强制硬性内存限制, 即只允许容器使用给定的内存
Docker也可以执行非硬性内存限制, 即容器可以使用尽可能多的内存, 除非内核检查到主机上的内存不够用了

2.1 内存相关选项

以下设置大部分的选项选取正整数, 跟着一个后缀, b,k,m,表示字节, 千字节, 兆字节,或者千兆字节
-m, --memory
容器可以使用的最大物理内存, 硬限制, 此选项最小允许值为4m, 此选项较为常用, 用来限制容器可以使用的最大物理内存
--memory-swap 
允许此容器交换到磁盘的内存量, 必须先用-m对内存现在才可以使用
-m 4m --memory-swap 4m
--memory-swappiness
设置容器使用交换分区的倾向性, 值越高表示越倾向于使用swap分区, 范围为0-100, 0为能不用就不用, 100为能用就用
--memory-reservation
允许指定小于--memory的软限制, 当Docker检测到主机上的争用或者内存不足时, 会激活该限制, 如果使--memory-reservation, 则必须将其设置为低于--memory才能使其优先生效. 因为它是软限制, 所以不能保证容器不超过限制
--kernek-memory
容器可以使用的最大内核内存量, 最小为4m, 由于内核与用户空间内存隔离, 因此无法与用户空间内存直接交换, 因此内核内存不足的容器可能会阻塞宿主机资源, 这会对主机和其他容器或者其他服务进程产生影响, 因此不要设置内核内存大小
--omm-kill-disable
默认情况下, 如果发生内存不足(OOM)错误, 则内核将终止容器中的进程. 要更改此行为, 可以使用--oom-kill-disable选项. 仅在设置了该-m/--memory选项的容器上禁用OOM. 如果-m未设置该标示, 则主机可能会用完内存, 内核可能需要终止主机系统的进程以释放内存

范例: MySQL内存限制

root@Ubuntu-1804-3:~# docker run -e MYSQL_ROOT_PASSWORD=123456 --rm -it -m 1g --oom-kill-disable mysql:5.7.29
-m MySQL容器最大使用1g物理内存, 是硬限制
--oom-kill-disable 表示即使发生内存OOM的情况, 也不会杀掉该容器

2.2 swap限制

k8s环境要求关闭swap
纯docker环境需要限制swap使用
--memory-swap 只有在设置了 --memory后才会有意思. 使用swap可以让容器将超出限制部分的内存置换到磁盘上. 不过经常将内存交换到磁盘的应用程序会降低性能

不同的--memory-swap设置会产生不同的效果

--memory-swap   --memory      功能
正数S             正数M        容器可用总空间(内存和交换分区)为S, 其中内存ram为M, 则swap为(S-M), 若S=M, 则无可用swap资源
0                 正数M       相当于未设置swap(unset)
unset             正数M       若主机(Docker Host)启用了swap, 则容器的可用swap为2*M
-1                正数M        若主机(Docker Host)启用了swap, 则容器可使用的主机上的所有swap空间
--memory-swap 值为正数, 那么--memory和--memory-swap都必须要设置, --memory-swap表示能使用的内存和swap分区的大小的总和, 例如: --memory=300m, --memory-swap=1g, 那么该容器能使用300m物理内存和700m swap空间, 即--memory是实际物理内存大小值不变, 而swap的实际大小计算方式为(--memory-swap)-(--memory)=容器可用的swap空间
--memory-swap 如果设置为0, 则忽略该设置, 并将该值视为未设置, 即不使用交换分区
--memory-swap 如果等于--memory的值, 并且--memory设置为正数, 容器无权访问swap
--memory-swap 如果未设置(unset), 如果宿主机开启了swap, 则实际容器的swap值最大为2*(--memory), 即两倍于物理内存大小, 例如, 如果--memory="300m",与--memory-swap没有设置, 该容器可以使用300m总的内存和600m交换空间, 但不准确(在容器中使用free命令所看到的swap空间并不精确, 毕竟每个容器都可以看到具体大小, 宿主机的swap是有上限的, 而且不是所有容器看到的累计大小)
--memory-swap 如果设置为-1, 如果宿主机开启了swap, 则容器可使用主机上swap的最大空间

在容器中执行free命令看到的是宿主机的内存和swap使用情况, 而非容器自身的swap使用情况

-m 2g: 容器最多使用2g内存
--memory-swap 3g: 容器最多使用的物理内存是3g, 包括2个g的内存和1个g的swap
root@Ubuntu-1804-3:~# docker run -it --rm -m 2g --memory-swap 3g alpine
/ # free -m
              total        used        free      shared  buff/cache   available
Mem:            962         248         301           9         412         569
Swap:          1905 (但是这里显示容器swap是2个g的限制)          5        1900
root@Ubuntu-1804-3:~# free -m
              total        used        free      shared  buff/cache   available
Mem:            962         248         300           9         412         569
Swap:          1905           5        1900 # 由此看到容器内查看free命令结果, 显示的就是宿主机的内存情况

3 容器的CPU限制

Linxu内存的进程调度基于CFS(Completely Fair Scheduler), 完全公平调度

服务器资源密集型

cpu密集型的场景:
优先级越低越好, 计算密集型任务的特点是进程大量的计算, 消耗cpu资源, 比如计算圆周率, 数据处理, 对视频进行高清解码等等, 全靠cpu的运算能力
IO密集型的场景: 优先级值高点, 涉及到网络, 磁盘IO的任务都是IO密集型任务, 这类任务的特点是cpu消耗很少, 任务的大部分时间都在等待IO操作完成
因为IO的速度远远低于cpu和内存的速度, 比如web应用, 高并发, 数据量大的动态网站来说, 数据库应该为IO密集型

cfs原理

cfd定义了进程的调度新模型, 它给cfs_rq(cfs的run_queue)中的每一个进程安排一个虚拟时钟vruntime. 
如果一个进程得以执行, 随着时间的增长, 其vruntime将不断增大, 没有得到执行的过程vruntime不变, 而调度器总是选择vruntime跑的最慢的那个进程来执行. 这就是所谓的完全公平调度. 为了区别不同优先级的进程, 优先级高的进程vruntime增长的慢, 以至于它可能得到更多的运行机会.
CFS的意义在于, 在一个混在着大量计算型进程和IO交互进程的系统中, CFS调度器相对其他调度器在对待IO交互进程要更加友善和公平
root@Ubuntu-1804-3:~# cat /sys/block/sda/queue/scheduler 
noop deadline [cfq] 

配置默认的CFS调度程序

默认情况下, 每个容器对主机的CPU周期的访问都是不受限制的, 可以设置各种约束, 以限制给定容器对主机CPU周期的访问. 
CFS适用于常规Linux进程的Linux内核CPU调度程序, 通过几个运行时标志, 可以配置对容器拥有的CPU资源的访问量. 使用这些设置时, Docker会在主机上修改容器cgroup的设置
--cpus=
制定一个容器可以使用多少个可用的CPU核心资源. 例如: 如果主机有两个CPU, 那么设置了--cpus="1.5", 则可以保证容器最多使用1.5个CPU. 如果宿主机是4核CPU, 那么还可以使用每个CPU上的一部分, 但是总计是1.5核心总的CPU.
--cpuset-cpus 进行容器和cpu绑定
用于指定容器运行的cpu编号, 也就是所谓的cpu绑定. 如果一个或多个cpu, 则容器可以使用逗号分隔的列表或连字符分隔的cpu范围. 第一个cpu编号为0, 有效值可以是0-3, (表示使用第1,2,3,4核cpu)或者1,3表示第2和4核cpu
--cpu-shares
用于设置cfs中调度的相对最大比例权重, cpu-shares的值越高的容器, 将会分得更多的时间片, 比如, 宿主机多核cpu总数为100%, 假如容器A为1024, B为2048, 那么容器B将使用最大的CPU分片是容器A可用CPU分配的两倍)
默认的时间片为1024, 最大是262144, 这是一个软限制
上一篇下一篇

猜你喜欢

热点阅读