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

问题描述 投票:2回答:2

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

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

java docker microservices amazon-ecs
2个回答
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(驻留集大小)统计量应该给你一个合理的基线。


2
投票

运行基准测试可能是正确的方法,但实际上,对于您所拥有的每个微服务来说,这样做可能会非常昂贵。一方面没有基准测试,就无法猜测微服务在负载下如何表现,例如由于GC,减少的内存会增加请求处理时间。另一方面,与开发人员的时间相比,RAM相对便宜,而分布式系统的写作基准则非常难。

我不相信没有公式可以在纸上计算。答案取决于每个微服务的实现和使用。它必须是一个持续的测试和监视周期,如果发现问题,则应调整内存设置以解决它。

通常,投资监控应该比编写一套基准测试产生更好的回报。

© www.soinside.com 2019 - 2024. All rights reserved.