当前位置: 代码迷 >> java >> 如何使用Docker确定Java微服务的堆大小/非堆大小?
  详细解决方案

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

热度:92   发布时间:2023-07-31 13:36:03.0

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

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

从Java 8u131开始, 。 因此,如果您运行类似:

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

有关于该主题的更多示例,并且还建议使用-XX:MaxRamFraction=1来允许使用“所有内存”,在此您已使用-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在他们的答案中建议的那样,您确实需要进行一些分析和监视才能为此实际选择正确的数字。 在本地运行应用程序并监视pstopRSS (驻留集大小)统计信息应该为您提供一个合理的基准。

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

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

通常,与编写一系列基准相比,对监视进行投资应该会产生更好的回报。

  相关解决方案