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

时间:2019-02-14 23:46:34

标签: java docker microservices amazon-ecs

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

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

运行基准测试可能是正确的方法,但是在实践中,为您拥有的每个微服务执行此测试可能会非常昂贵。一方面,如果没有基准测试,就无法猜测微服务在负载下的行为,例如由于GC,减少的内存将增加请求处理时间。但是另一方面,与开发人员的时间相比,RAM相对便宜,坦白地说,为分布式系统编写基准测试很困难。

我不认为没有公式可以在纸上计算出来。答案将取决于每种微服务的实现和用法。它必须是不断测试和监视的周期,如果发现问题,则应调整内存设置以解决问题。

通常,投资于监视应该比编写一系列基准产生更好的回报。