我们正在AWS ECS中运行Java微服务。因此,对于Docker,我们使用-Xmx指定了一些硬Java堆限制。确定要为堆保留多少内存以及为非堆内存(元空间,堆栈,JIT缓存等)需要多少是非常棘手的部分。 当前,我们正在运行压力测试以识别何时拥有Docker OOMKiller 。 例如,对于2GB的AWS任务(码头工人),最大可以为堆设置-Xmx1400m(对于-Xmx1450m,我们没有足够的内存来存储非堆的东西(退出代码137)) 实际上,Java 10+具有“ -XX:MaxRAMPercentage”,但我们仍然需要知道该百分比。
如何确定Java微服务的堆大小/非堆大小?还是压力测试是唯一的解决方案?
答案 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在他们的答案中建议的那样,您确实需要进行一些分析和监视,才能为此实际选择正确的数字。在本地运行应用程序并监视RSS
或ps
中的top
(居民集大小)统计信息应该为您提供一个合理的基准。
答案 1 :(得分:2)
运行基准测试可能是正确的方法,但是在实践中,为您拥有的每个微服务执行此测试可能会非常昂贵。一方面,如果没有基准测试,就无法猜测微服务在负载下的行为,例如由于GC,减少的内存将增加请求处理时间。但是另一方面,与开发人员的时间相比,RAM相对便宜,坦白地说,为分布式系统编写基准测试很困难。
我不认为没有公式可以在纸上计算出来。答案将取决于每种微服务的实现和用法。它必须是不断测试和监视的周期,如果发现问题,则应调整内存设置以解决问题。
通常,投资于监视应该比编写一系列基准产生更好的回报。