10 | Swap:容器可以使用Swap空间吗?

本文仅作为学习记录,非商业用途,侵删,如需转载需作者同意。

swap空间:
它就是一块磁盘空间,当内存写满的时候,就可以把内存中不常用的数据暂时写到这个 swap 空间上,这样一来内存空间就可以释放出来,用来满足新的内存申请的需求。

它的好处是可以应对一些瞬时突发的内存增大需求,不至于因为内存一时不够而触发OOM killer,导致进程被杀死。

那么容器里使用 swap 有什么影响呢?

一、问题再现

在一个有swap的机器上启动一个容器,设置好memory cgroup 限制。

创建swap的命令:

https://github.com/chengyli/training/blob/main/memory/swap/create_swap.sh

运行free 命令,可以看到机器上的内存空间,这里swap有20G。

在这里插入图片描述

使用OOM 那一讲中的例子

https://github.com/chengyli/training/blob/main/memory/oom/start_container.sh

再启动一个容器,Memory Cgroup 限制为 512MB,容器中的 mem_alloc 程序去申请2G内存。

这次和上次情况不一样,容器没有发生OOM。从下面的图中可以看到 mem_alloc 进程的 RSS(常驻)内存一直在 512MB(RES : 515596)左右。
在这里插入图片描述
我们再看下 swap 空间,使用了 1.5GB(used 1542144 KB),输出的结果如下图,简单计算一下 1.5GB + 512MB ,正好是 mem_alloc 这个程序申请的2GB 内存。

在这里插入图片描述

有了swap 空间,这里的容器没有被OOM Killer了。
但是这样也失去了 Memory Cgroup 限制的作用。

如果一个容器中的程序发生了内存泄露(Memory leak),本来 Memory Cgroup 可以及时的杀死这个进程,让它不影响整个节点中的其他应用程序,结果现在这个内存泄漏的程序没被杀死,还会不断的写入 swap 磁盘反而影响了整个节点的性能。

是否使用swap空间,在不同的场景有不同的取舍。如果有同一个节点上的两个容器有冲突的时候,一个开启swap更好,一个需要不开启,通过Memory Cgroup进行严格的限制,怎么办呢。

二、如何正确理解swappiness 参数

参数文件位置:/proc/sys/vm/swappiness

swappiness

This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase aggressiveness, lower values decrease the amount of swap. A value of 0 instructs the kernel not to initiate swap until the amount of free and file-backed pages is less than the high water mark in a zone.

The default value is 60.

swappiness可以决定系统将会有多频繁的使用交换分区

值越大:内核更频繁的使用交换分区
值越小:内核会尽量避免使用交换分区

swappiness 的取值范围是 0-100 ,默认是60


上一节说到了两种内存类型:Page Cache和RSS

在有磁盘文件访问的时候,Linux会尽量把系统的空闲内存用作Page Cache 来提供文件的读写性能,在没有打开 swap 空间的情况下,一旦内存不够,这种情况下就只能把Page Cache 释放了,而RSS 内存是不能释放的。

在RSS 里的内存,大部分都是没有对应磁盘文件的内存,比如用 malloc() 申请得到的内存,这种内存也被称为匿名内存(Anonymous memory)。 当Swap空间打开后,可以写入swap 空间的,就是这些匿名内存。

开启swap时,在内存紧张时,Linux系统怎么决定是先释放 Page Cache,还是先把匿名内存释放并写入到swap空间里呢。

分析如下,可能发生下面两种情况:
1、系统先把Page Cache都释放了,一旦节点里有频繁的文件读写操作,系统的性能就会下降。
2、Linux 系统先把匿名内存都释放并写入到swap,一旦这些释放的匿名内存马上需要使用,又需要从swap空间读回到内存中,这样又会让swap的读写频繁(其实也是磁盘),导致系统性能下降。

显然,我们在释放内存的时候,需要平衡 Page Cache 的释放和匿名内存的释放,而swappiness ,就是用来定义这个平衡的参数。

2.1、swappiness 参数

swappiness 值得范围是0-100,这个值不是百分比,更像一个权重,用来定义Page Cache 内存和匿名内存释放的一个比例。


        /*
         * With swappiness at 100, anonymous and file have the same priority.
         * This scanning priority is essentially the inverse of IO cost.
         */

        anon_prio = swappiness;
        file_prio = 200 - anon_prio;

看上面的代码,分三种情况讨论:

  • 当swappiness的值是100的时候,匿名内存和Page Cache的释放比例是100:100,也就是等比例释放了。
  • swappiness缺省值是60的时候,匿名内存和Page Cache 内存的释放比例就是60:140,Page Cache 内存的释放要优于匿名内存。
  • 当swappiness的值是0时:

当空闲内存少于内存一个 zone 的“high water mark” 中的值的时候,Linux还是会做内存交换,也就是把匿名内存写入到Swap 空间后释放内存。
zone 是Linux 划分物理内存的一个区域,里面有3个水位线(water mark),水位线用来警示空闲内存的紧张程度。

做个验证:

echo 0 > /proc/sys/vm/swappiness 命令把swappiness 设置为0,然后用之前的例子里的 mem_alloc 程序来申请内存。

比如节点内存12GB,2GB的swap空间,用mem_alloc 申请12GB 的内存。 申请之前swap 的使用是0。

在这里插入图片描述

接下来,调用mem_alloc 之后,swap空间就被使用了。

在这里插入图片描述

因为mem_alloc 申请12GB 内存已经和节点最大内存差不多了,如果查看 cat /proc/zoneinfo ,也可以看到 normal zone 里 high(water mark)的值和free 的值差不多,这样在 free < high 就是超过警示线的时候,系统就会回收匿名内存页面并写入swap 空间。

在这里插入图片描述

swappiness 的取值范围是0-100, 值100时系统平等回收匿名内存和Page Cache 内存,一般缺省值是60,就是优先回收 Page Cache,即使swappiness为0,也不能完全禁止swap分区使用,在内存紧张的时候,也会使用swap来回收匿名内存

三、解决问题

使用了Memory Cgroup 之后,在Memory对应的控制组下有个memory.swappiness 参数。

改参数可以控制这个 Memory Cgroup 控制组下面匿名内存和Page Cache 的回收。 取值的范围和工作方式和全局的 swappiness 差不多。 这里有一个优先顺序,在memory
Cgroup 的控制组里,如果你设置了 memory.swappiness 参数,它就会覆盖全局的。

容器中有一点不同:当memory.swappiness=0 的时候,对匿名内存的回收始终是禁止的,也就是始终都不会使用swap空间

这时Linux 系统就不会再去比较free 内存和 zone 里的 high water mark 的值,再决定一个Memory Cgroup 中的匿名内存要不要回收。

这样 memory.swappiness 参数就可以让需要使用 swap 空间的容器,和不需要使用 swap 的容器同时运行在同一个宿主机上。

四、重点总结

swappiness 参数值的作用是,在系统里有swap空间之后,当系统需要回收内存的时候,是优先释放 Page Cache 中的内存还是优先释放匿名内存(也就是写入swap)

swappiness的取值范围在 0-100 之间,我们可以记住下面三个值:

  • 值为100时,释放Page Cache 和匿名内存是同等优先级的
  • 值为60时,这是大多数Linux 系统的缺省值,这时候Page Cache 的释放优先级高于匿名内存的释放。
  • 值为0时,当系统中空闲内存低于一个临界值的时候,仍然会释放匿名内存并把页面写入swap空间。

在这里插入图片描述

swappiness 参数除了在 proc 文件系统下有个全局的值外,在每个Memory Cgroup 控制组里也有一个 memory.swappiness 。

每个Memory Cgroup 控制组里的swappiness 参数值为0的时候,就可以让控制组里的内存停止写入 swap。

有了 memory.swappiness 这个参数后,需要使用 Swap 和不需要 Swap 的容器就可以在同一个宿主机上同时运行了,这样对于硬件资源的利用率也就更高了。

五、评论

1、
问题:k8s下容器貌似不能用swap
回答: kubelet缺省不能在打开swap的节点上运行。
配置“failSwapOn: false”参数,kubelet可以在swap enabled的节点上运行。

2、
问题:对于最近k8s宣布放弃docker有什么看法?
回答:对于k8s来说,的确没有必要再用docker了。
这是我们组之前做的从docker切换到containerd的技术分享:
https://www.infoq.cn/article/odslclsjvo8bnx*mbrbk

3、
问题:Memory Cgroup 参数memory.swappiness 起到局部控制的作用,前提是节点开启了swap 功能。
回答:是的。

4、
问题:既然memory.swappiness设置为0了,Swap分区是不会有数据写入的。
回答:是的

5、
问题:对于开启了swap,且swap空间够大的前提下,goup的mem limit没用咯?
回答:是的, 如果只是设置 memory.limit_in_bytes。

6、
问题:已经设置memory.swappiness参数,全局参数swappiness参数失效,那么容器里就不能使用swap了。
回答:是的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值