我们当前在 Google Container Engine (GKE) 中运行的 Kubernetes 集群由n1-standard-1
运行 Debian GNU/Linux 7.9 (wheezy) 的机器类型(1 个虚拟 CPU 和 3.75 GB 内存)组成,该版本由 Google 维护。由于我们服务的负载和内存使用量增加,我们需要将节点升级到更大的机器类型。在我们的测试集群中尝试此操作时,我们遇到了一些(对我们来说)似乎相当奇怪的事情。
JVM 应用程序部署到 Google 节点时所消耗的内存似乎与节点上可用的核心数成正比。即使我们将 JVM 最大内存 (Xmx) 设置为 128Mb,在 1 核机器上也会消耗大约 250Mb(这是可以理解的,因为 JVM 消耗的内存比最大限制要多,这是由于 GC、JVM 本身等原因),但在 2 核机器上消耗大约 700Mb(n1-standard-2
),在 4 核机器上消耗大约 1.4Gb(n1-standard-4
)。唯一不同的是机器类型,使用的 Docker 映像和配置完全相同。
例如,如果我使用某种n1-standard-4
机器类型通过 SSH 进入一台机器并运行,sudo docker stats <container_name>
我会得到这样的结果:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
k8s.name 3.84% 1.11 GB / 1.611 GB 68.91% 0 B / 0 B
当我运行相同的具有精确的 Docker 映像相同的(应用程序)本地配置(mac osx 和 docker-machine)我看到:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
name 1.49% 236.6 MB / 1.044 GB 22.66% 25.86 kB / 14.84 kB 0 B / 0 B
这与我根据设置所期望的结果更加一致Xmx
(记录显示我有 8 个核心和 16GB 内存)。当我top -p <pid>
在 GKE 实例上运行时,也证实了同样的情况,它为我提供了 1.1 到 1.4 Gb 的 RES/RSS 内存分配。
Docker 镜像定义如下:
FROM java:8u91-jre
EXPOSE 8080
EXPOSE 8081
ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF-8
# Add jar
ADD uberjar.jar /data/uberjar.jar
CMD java -jar /data/uberjar.jar -Xmx128m -server
我也尝试过添加:
ENV MALLOC_ARENA_MAX 4
我已经在多个帖子中看到推荐,例如这但似乎没有任何区别。我也尝试过更改为另一个 Java 基础映像以及使用 alpine linux,但这似乎也没有什么改变。
我本地的 Docker 版本是 1.11.1,Kubernetes/GKE 中的 Docker 版本是 1.9.1。Kubernetes 版本(如果有关系)是 v1.2.4。
同样有趣的是,如果我们将 pod/容器的多个实例部署到同一台机器/节点,某些实例将分配更少的内存。例如,前三个可能分配 1.1-1.4Gb 内存,但随后的 10 个容器每个仅分配约 250 Mb,这大致符合我的预期每一个实例分配。问题是,如果我们达到机器的内存限制,前三个实例(分配 1.1Gb 内存的实例)似乎永远不会释放它们分配的内存。如果它们在机器压力增加时释放内存,我不会担心这个问题,但由于它们在机器加载时仍保留内存分配,因此这成为一个问题(因为它禁止在此机器上安排其他容器,因此浪费了资源)。
问题:
- 什么原因导致了这种行为?是 JVM 问题吗?Docker 问题?VM 问题?Linux 问题?配置问题?或者是两者兼而有之?
- 在这种情况下我可以尝试做些什么来限制 JVM 的内存分配?
答案1
当您指定
CMD java -jar /data/uberjar.jar -Xmx128m -server
然后,您想要作为 JVM 参数的值 ( -Xmx128m -server
) 将作为命令行参数传递给 .jar 文件中的 Main 类。它们可用作方法中的参数public static void main(String... args)
。
请注意,如果您按名称运行主类而不是指定可执行文件,也是如此jar
。
要将它们作为 JVM 参数传递,而不是将其作为程序的参数传递,您需要在参数之前指定它们-jar
。
答案2
问题出在 中指定的 JVM 设置上Dockerfile
。我们像这样启动了 JVM:
CMD java -jar /data/uberjar.jar -Xmx128m -server
但当我们切换到:
CMD java -Xmx128m -server -jar /data/uberjar.jar
设置已被考虑在内。我仍然不明白为什么我没有在本地看到这个问题,但我很高兴我们设法解决了这个问题。