【发布时间】:2019-05-14 02:22:11
【问题描述】:
我正在开发一个 java 服务,它基本上在网络文件系统中创建文件来存储数据。它在 Ubuntu 18.04 LTS 的 k8s 集群中运行。 当我们开始限制 kubernetes 中的内存(limits: memory: 3Gi)时,pods 开始被 kubernetes OOMKilled。
一开始我们以为是java进程的内存泄漏,但深入分析发现问题出在内核的内存上。 我们验证了查看文件 /sys/fs/cgroup/memory/memory.kmem.usage_in_bytes
我们将这种情况隔离为仅使用 DD 命令创建文件(没有 java),如下所示:
for i in {1..50000}; do dd if=/dev/urandom bs=4096 count=1 of=file$i; done
使用 dd 命令,我们看到同样的事情发生了(内核内存增长到 OOM)。 k8s重启pod后,我开始做describe pod:
- 最后状态:终止
- 原因:OOMKilled
- 退出代码:143
创建文件会导致内核内存增长,删除这些文件会导致内存减少。但是我们的服务存储数据,所以它会不断地创建很多文件,直到 Pod 因为 OOMKilled 而被杀死并重新启动。
我们测试了使用带有 --kernel-memory 参数的独立 docker 来限制内核内存,它按预期工作。内核内存增长到极限,不再上升。但是我们没有在 Kubernetes 集群中找到任何方法来做到这一点。 有没有办法限制 K8S 环境中的内核内存? 为什么文件的创建会导致内核内存增长而没有被释放?
【问题讨论】:
-
我猜你正在设置像kubernetes.io/docs/concepts/configuration/… 这样的限制,而你已经查看了github.com/kubernetes/kubernetes/issues/61937 ?
-
一个java进程正在运行吗?文件是否正在写入持久卷?
-
你好@RyanDawson。此问题发生在写入文件的 java 进程和写入文件的其他程序(非 java)中。我们可以使用 java 和非 java 程序以及 DD linux 命令重现此问题。对于 java 程序,java 使用的内存不会增长。问题是内核内存。好像写文件需要内存内核,没有释放。我们正在将文件写入持久卷中,无论是在本地磁盘中还是在 nfs 中。结果是一样的
-
这个问题很容易重现。我很惊讶,网上没有很多类似的案例
-
我们在部署中添加(感谢您的帖子)以下内容:
initContainers: - name: init-sysctl image: busybox command: - /bin/sh - -c - | sysctl -w vm.vfs_cache_pressure=value securityContext: privileged: true
标签: docker linux-kernel kubernetes out-of-memory