linux容器内存占用居高不下怎么解决
本篇内容主要讲解“linux容器内存占用居高不下怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux容器内存占用居高不下怎么解决”吧!
成都创新互联专业为企业提供民勤网站建设、民勤做网站、民勤网站设计、民勤网站制作等企业网站建设、网页设计与制作、民勤企业网站模板建站服务,10余年民勤做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
疑问
在出现系统内存过高的情况下,我们可以通过 free -m
来查看当前系统的内存使用情况:
在发现是系统内存占用高后,就有读者提到,为什么不 “手动清理 Cache”,因为 Cache 高的话,可以通过 drop_caches 的方式来清理:
清理 page cache:
$ echo 1 > /proc/sys/vm/drop_caches
清理 dentries 和 inodes:
$ echo 2 > /proc/sys/vm/drop_caches
清理 page cache、dentries 和 inodes:
$ echo 3 > /proc/sys/vm/drop_caches
但新问题又出现了,因为我们的命题是在容器中,在 Kubernetes 中,若执行 drop_caches 相关命令,将会对 Node 节点上的所有其他应用程序产生影响,尤其是那些占用大量 IO 并由于缓冲区高速缓存而获得更好性能的应用程序,可能会产生 “负面” 后果。
表象
回归原始,那就是为什么要排查这个问题,本质原因就是容器设置了 Memory Limits,而容器在运行中达到了 Limits 上限,被 OOM 掉了,所以我们想知道为什么会出现这个情况。
在前文中我们针对了五大类情况进行了猜想:
频繁申请重复对象。 不知名内存泄露。 madvise 策略变更。 监控/判别条件有问题。 容器环境的机制。
在逐一排除后,后续发现容器的 Memory OOM 判定标准是 container_memory_working_set_bytes 指标,其实际组成为 RSS + Cache(最近访问的内存、脏内存和内核内存)。
在排除进程内存泄露的情况下,我们肯定是希望知道 Cache 中有什么,为什么占用了那么大的空间,此时我们可以通过 Linux pmap 来查看该容器进程的内存映射情况:
在上图中,我们发现了大量的 mapping 为 anon 的内存映射,最终 totals 确实达到了容器 Memory 相当的量,那么 anon 又是什么呢。实质上 anon 行表示在磁盘上没有对应的文件,也就是没有实际存在的载体,是 anonymous。
思考
既然存在如此多的 anon,结合先前的考虑,我们知道出现这种情况的服务都是文件处理型服务,包含大量的批量生成图片、生成 PDF 等资源消耗型的任务,也就是会瞬间申请大量的内存,使得系统的空闲内存触及全局最低水位线(global wmark_min),而在触及全局最低水位线后,会尝试进行回收,实在不行才会触发 cgroup OOM 的行为。
那么更进一步思考的是两个问题,一个是 cgroup 达到 Limits 前的尝试释放仍然不足以支撑所需申请的连续内存段,而另外一个问题就是为什么 Cache 并没有释放:
通过上图,可以肯定该服务在凌晨 00:00-06:00 是没有什么流量的,但是 container_memory_working_set_bytes 指标依旧稳定不变,排除 RSS 的原因,那配合指标的查看基本确定是该 cgroup 的 Cache 没有释放。
而 Cache 的占用高,主要考虑是由于其频繁操作文件导致,因为在 Linux 中,在第一次读取文件时会将一份放到系统 Cache,另外一份则放入进程内存中使用。关键点在于当进程运行完毕关闭后,系统 Cache 是不会马上回收的,需要经过系统的内存管理后再适时释放。
但我们发现 Cache 的持续不释放,进程也没外部流量,RSS 也低的可怜,Cache 不像被进程占用住了的样子(这一步的排除很重要),最终就考虑到是否 Linux 内核在这块内存管理上存在 BUG 呢?
根因
问题版本
该服务所使用的 Kubernetes 是 1.11.5 版本,Linux 内核版本为 3.10.x,时间为 2017 年 9 月:
$ uname -aLinux xxxxx-xxx-99bd5776f-k9t8z 3.10.0-693.2.2.el7.x86_64 #1 SMP Tue Sep 12 22:26:13 UTC 2017 x86_64 Linux
都算是有一定年代的老版本了。
原因分析
memcg 是 Linux 内核中管理 cgroup 内存的模块,但实际上在 Linux 3.10.x 的低内核版本中存在不少实现上的 BUG,其中最具代表性的是 memory cgroup 中 kmem accounting 相关的问题(在低版本中属于 alpha 特性):
slab 泄露:具体可详见该文章 SLUB: Unable to allocate memory on node -1 中的介绍和说明。
memory cgroup 泄露:在删除容器后没有回收完全,而 Linux 内核对 memory cgroup 的总数限制是 65535 个,若频繁创建删除开启了 kmem 的 cgroup,就会导致无法再创建新的 memory cgroup。
当然,为什么出现问题后绝大多数是由 Kubernetes、Docker 的相关使用者发现的呢(从 issues 时间上来看),这与云原生的兴起,这类问题与内部容器化的机制相互影响,最终开发者 “发现” 了这类应用频繁出现 OOM,于是开始进行排查。
解决方案
调整内核参数
关闭 kmem accounting:
cgroup.memory=nokmem
也可以通过 kubelet 的 nokmem Build Tags 来编译解决:
$ kubelet GOFLAGS="-tags=nokmem"
但需要注意,kubelet 版本需要在 v1.14 及以上。
升级内核版本
升级 Linux 内核至 kernel-3.10.0-1075.el7 及以上就可以修复这个问题,详细可见 slab leak causing a crash when using kmem control group,其在发行版中 CentOS 7.8 已经发布。
到此,相信大家对“linux容器内存占用居高不下怎么解决”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
当前标题:linux容器内存占用居高不下怎么解决
地址分享:http://azwzsj.com/article/igeisc.html