内存资源限制

我们先看下面重点的一些知识点。

9.1.1 重点提示

CGroup:

Cgroup 是 control group (控制组)的缩写,cgroup就是我们docker里面真正去限制每个不同的容器它的使用资源大小的这么一个底层技术,cgroup是由 Linux 内核提供的,可以限制、记录、隔离进程组(process groups)之前我们也说过在我们的 Linux 里面,docker 每一个不同的容器相当于就是每一个不同的进程,对于外部的宿主机而言。那既然是每一个不同的进程我们就可以通过 Linux 内核提供隔离进程组技术,去进行资源隔离。隔离的物理资源主要有 CPU、内存、I/O 等等。2007年就进入了 Linux 2.6.24 内核,如果是比2.6.24 老的版本就不能去使用 cgroup ,cgroup 不是完全制造,他是将进程管理器从 cpuset 中剥离出来,作者是谷歌的 paul menage 。cgroup才是我们在 docker 对我们容器使用资源隔离的这么一个真正的底层技术。

默认情况下,如果不对容器做任何限制,容器能够占用当前系统给予容器提供的所有资源。因为只要有对应的资源能够给他,他就能够全部用掉,当然前提是容器里的进程再去占用的情况下。假如容器中的进程不用给他也白搭。也就意味着容器内部的工作进程他对于资源的所需量是无止无尽的。也就是宿主机有多少容器就能够用多少,这样的话我们整个宿主机的资源全部都会一个容器所占用。

docker限制可以从 内存、cpu、磁盘I/O 这三个方面去考虑,但是在本文中只会讲内存和CPU的限制,磁盘I/O由于使用不多所以本文不会提及。因为在真正生产环境中我们的容器目录都是通过 -v 选项从别的地方挂载过来的。

我在这文中提及这么多,需要理解的一个点就是。如果不对容器做限制,容器内部的进程对资源所需要的是无穷无尽的话,会造成操作系统的瘫痪。难道 Linux 内核就没有防御的机制吗?当然是有的就是我们的OOME 内核的一个机制。

OOME:out of memory exception (内存不足异常错误)

这是我们的 Linux 内核自身的一种保护机制,除了 init 和我们的centos6 中system,位于绝对不会关闭的这么一个机制,其他的所有资源都有可能被随机删除。也就意味着如果有一天我们的 Linux 内核自己的内存都不够了,但是外部用户空间还有一些其他的进程在工作,这时候就会随机的杀死这些用户空间内的一些进程,来保证自己 Linux 内核的运行。但是他的杀除机制也不是这么随意的,它是会根据对应的权重关系,比如现在我们在用户空间中有这么几个进程,有一个权重最高,他就会将那些权重低的进程全部杀掉,如果还不够的话再会杀掉这个权重高的。

一旦发生 OOME,任何进程都可能被杀死,包括docker daemon 在内

所以在这种情况下,docker daemon(docker 守护进程)也有可能会被杀死,一旦docker daemon 被杀死所有的容器也会全部死掉。

为此,docker 调整了 docker daemon 的 OOME 优先级,来避免被内核关闭。也就意味着可能会被杀死其他不同的容器。

总结:

  • Cgroup是我们容器资源限制的底层技术。

  • 限制方面:可以从内存、CPU、磁盘I/O 角度出手

  • 如果不对容器做任何限制,容器是可以使用宿主机所有的资源,既然能够使用所有宿主机的资源,就可能会造成我们宿主机的资源不够,比如内核内存不够了,这种情况下我们就会启动 OOME 的机制,为了防止 OOME 会误删除 docker daemon ,所以 docker daemon 的 oome 优先级会比较高,不会被删除。但是我们启动的一些容器也是在 Linux 中,并且也是进程的方式存在的,这些容器的进行就可能被随机删除(可能会删除一些重要服务的容器)。所以对于内存的限制来说我们是比较常去做的这么一件操作

9.1.2 生产环境中必须注意的几个事项

1、为应用做内存压力测试,理解正常业务下需要使用的内存情况,然后再进入到生产环境中使。

2、一定要限制容器的内存使用上限。

3、尽量保证主机的资源充足,一旦监控发现资源不足,就进行扩容或者对容器进行迁移。所以监控服务器zabbix非常重要

4、如果可以(内存资源充足的情况下),尽量不要使用 swap,swap 会导致内存计算复杂,对调度器极度不友好。对调度器不友好的结果可能就会造成一些资源分配的不均,在kubernetes中的资源调度器甚至默认情况下都不使用 swap 进行当作内存的分配。

9.1.3 设置方式

那怎么样去做一些设置呢,在docker 启动参数中,和内存限制有关的包括(参数的值一般是内存大小,也就是一个正数,后面跟着内存单位 b、k、m、g ,分别对应的是 bytes、KB、MB、GB)。

参数如下:

-m --memory#容器额能够使用的最大的内存大小,最小值为 4M,如果一个容器他的内存大小都不够 4M的话没有什么进程能够起得来,这个最小值 4M是docker 进程本身的限制,如果小于 4M docker不让我们采用,这个相当于是一个硬限制

--memory-swap#容器能够使用的 swap 大小,但是需要注意的就是这里设置的 memory swap 使用的容器大小并不是swap的大小,他是有一个计算量的

--memory-swappiness#默认情况下,主机可以把容器使用的匿名页 swap 出来(交换出来),你可以设置一个0-100 之间的值,代表允许 swap 交换出来的比例。 那这是什么含义呢,也就意味着在正常情况下,我们主机能够使用的这么一个内存的交换页或者叫匿名页。那这个 0-100 的值呢,代表的含义就是比如举个例子。我如果设置的是 40 那默认情况下我会先把我们的整个内存中的百分之40的资源先给利用到,也就是允许利用百分之 40 的资源,那剩下的由我们的交换分区去补充,那如果是 0 的话代表完全不用我们的交换分区页,这样的话是不是效率更高,所以这个设置我们一般都不会去采用,而是通过 Linux内核去调用,即使要设置的话也是设置为 10 。

--memory-reservation#设置一个内存使用的 soft limit,也就是软件的最小值,设置值必须小于 -m 设置,这个相当于是我们内存资源的一个软限制。

--kernel-memory#容器能够使用的内核内存使用大小,也就是我们整个容器里内核的使用大小,包括我们的一些套接字使用内存、tcp链接使用的内存等等都在我们的限制范围之内,一般来说我们不进行限制。

--oom-kill-disable#是否允许 OOM 的时候杀死我们的容器。如果只设置了 -m ,才可以把这个选项设置为 false , false 代表的含义就是这个容器不被 oom 所杀死,那如果我们没有设置 -m 的话并且还设置为 false的话也就意味着非常有可能造成的就是,比如这个容器他会一直去调用我们的系统资源,调用的最后的结果就是除了这个容器以外,其他容器全部死了,原因是 false 告诉容器了不能别 OOM 机制退出,但是这个容器它又无限的去要资源,这时候只能够杀其他的容器来弥补他的内存使用,并不止其他的容器还有主机上的其它一些进程都会被杀死。所以在使用这个选项的时候一定要注意,这个参数一般我们都不设置,因为容器它有治愈机制,即使宕掉了他也会启动补充一个,但是加了这个参数之后就会很可能造成上面这种情况。如果想设置的话先设置 -m 他的硬限制是多大之后再去设置 false 

软限制和硬限制区别:

也就意味着我们加了 -m 以后这个容器最多也不能够超过我们 -m 设置的这个大小,但是如果我设置了一个软限制,并且这个软限制为 10MB,硬限制为 20MB ,这时候是可以允许超过 10mb 的,举个例子,比如现在我们主机的资源现在非常非常之多,那这时候如果容器他的软限制利用空间超过 10MB了允许上去。但是绝对不能够超过硬限制的 20MB ,当我们的内存不够用的时候,那硬限制就会将他压缩回软限制的 10MB 。可以允许临时的跃升,跃升为我硬限制的最大限制。软限制就是这么一个含义,但是当内存不够用的时候又会被压回软限制。所以相当于给了容器内存使用的一定浮动空间。

9.1.3.1 设置解释

首先上图中会有一堆不同情况的存在,第一个选项是 –memory-swap,第二个选项是 –memory,第三个是功能。

  • 当 –memory-swap 设置为正数 S 时,–memory 设置为正数 M 时,那容器可用的总空间也就是总内存大小为 S,其中我们真正的物理内存可用为 M ,交换分区内存为 S-M ,也就意味着如果 –memory-swap 设置的是 10MB的话,然后–memory 设置为 4MB,那我们能够用到的物理内存大小是 4MB ,能够用到的虚拟内存S-M=10-4=6MB

    –memory-swap 设置的并不是 swap 的大小,而是 –memory和能够使用的虚拟内存相加的大小。

    若 S=M ,则无可使用的 swap 资源,也就意味着如果 –memory-swap 设置的为 4M –memory设置的也是4M ,最终的结果就是只有我们的物理内存使用,我们的 swap 交换空间允许使用的为0。

  • 如果 –memory-swap 设置的为0 –memory 设置为正数的话,相当于没有设置swap,没有设置swap相当于swap的可用大小为两倍的 M ,也就意味着 –memory-swap 设置为0,–memory 设置为4,那它们两个加在一起能够使用的内存大小就是 12,原因就是 –memory-swap 设为0也就是相当于未设置 swap默认值就是 M的两倍等于 8M,然后8+4=12M

  • 那下一个选项也是一样,只不过是两种不同的写法,一个是不设置一个是设置为0 都代表 unset 需要大家注意一下

  • 还有一个参数就是 –memory-swap 等于 -1 ,–memory 正数,这种情况下相当于就是容器可以使用我们的外层主机的最大的swap分区,也就是 –memory 设置为 4 ,–memory-swap 设置为-1,那能够使用的物理内存大小为 4 MB,那能够使用 swap 空间的大小为宿主机的所有。(一般来说这种情况使用的非常的小,基本上不在我们的生产环境中使用swap分区的)

注意:

在容器内部使用 free 命令看到的 swap 空间并没有真实含义。

点赞