如何使用Docker确定Java微服务的堆大小/非堆大小?

2019年8月25日 66点热度 0条评论

我们正在AWS ECS中运行Java微服务。因此,对于Docker,我们使用-Xmx指定了一些硬Java堆限制。确定要为堆保留多少内存以及为非堆内存(元空间,堆栈,JIT缓存等)需要多少是非常棘手的部分。当前,我们正在运行压力测试以识别何时拥有Docker OOMKiller。
例如,对于2GB的AWS任务( docker ),最大可以为堆设置-Xmx1400m(对于-Xmx1450m,我们没有足够的内存来存储非堆的东西(退出代码137))
实际上,Java 10+具有“-XX:MaxRAMPercentage”,但是我们仍然需要知道该百分比。

如何确定Java微服务的堆大小/非堆大小? 还是压力测试是唯一的解决方案?

解决方案如下:

从Java 8u131开始,there is an option to set the JVM limits based on container memory limits。因此,如果您运行类似:

docker run \
  -m 2g \     # set a container memory limit
  openjdk:8 \
  java \
    -XX:+UnlockExperimentalVMOptions \
    -XX:+UseCGroupMemoryLimitForHeap \
    com.example.Classname

JVM将设置堆限制,使其适合2 GB的容器内存限制,并为您运行
-Xmx。原则上,这应该安排事情,以便您永远不会达到容器的内存限制,而是先获取Java
OutOfMemoryError

This blog post关于该主题还有更多示例,并且建议
-XX:MaxRamFraction=1允许使用“所有内存”,在此您已通过
docker run -m选项对其进行了限制。

实际上,您可能会在Dockerfile中设置
$JAVA_OPTS,例如

FROM openjdk:8
COPY app.jar /
ENV JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRamFraction=1
CMD ["java", "-jar", "/app.jar"]

然后像

docker run -d -p ... -m 2g myimage

在Kubernetes环境中,在pod的资源约束中声明的内存限制起着相同的作用。

正如@KarolDowbecki在他们的答案中建议的那样,您确实需要进行一些分析和监视才能为此实际选择正确的数字。在本地运行应用程序并监视
RSS
ps中的
top(居民集大小)统计信息应为您提供一个合理的基准。