短短几年内,容器就改变了软件行业的面貌。也许您已经到了在容器中运行Java的地步。那很棒!不幸的是,关于容器化Java应用程序的CPU和内存使用率,还有一些事情要注意,我将在下面概述。
本文假定总体上熟悉Java和容器。如果您需要更多背景知识,请查看部分(或全部)参考资料。
如果有一个关于在容器中运行Java的关键声明,则为以下内容:
为什么?
设置容器内存(和CPU)限制。仅依靠资源请求(软限制)是不够的。软限制非常适合帮助调度程序,但是设置硬限制可以使Docker(或您使用的任何容器运行时)分配指定的资源给容器本身,而不再分配更多资源。这也将允许Java(从Java 8u191开始默认为“容器感知”)根据放置在容器本身上的资源限制(而不是容器正在运行的节点)正确分配内存。
[Min | Max | Initial] RAMPercentage
参数 在较新的Java版本中,引入了以下JVM参数(并将其反向移植到Java 8u191)。
-XX:MinRAMPercentage -XX:MaxRAMPercentage -XX:InitialRAMPercentage
我不会详细介绍它们是如何工作的,但是关键要点在于它们可以用于微调JVM堆大小,而无需直接设置堆大小。也就是说,容器仍然可以依靠施加在其上的限制。
那么使用什么正确的值呢?答案是-“取决于”……尤其是对容器施加的限制。
默认情况下,JVM堆获取容器内存的25%。您可以调整初始/最小/最大堆参数来更改此…例如设置-XX:MaxRAMPercentage = 50将允许JVM为堆消耗50%的容器内存,而不是默认的25%。什么时候安全,很大程度上取决于容器必须使用多少内存以及容器中正在运行哪些进程。
例如,如果您的容器正在运行一个Java进程,并为其分配了4 GB的RAM,并且您设置了 -XX:MaxRAMPercentage = 50
,则JVM堆将获得2 GB。这与通常会获得的1 GB默认值相反。在这种情况下,几乎可以肯定50%是绝对安全的,甚至是最佳的,因为许多可用RAM可能未得到充分利用。但是,假设同一容器仅分配了512 MB RAM。现在设置 -XX:MaxRAMPercentage = 50
将为堆提供256 MB的RAM,而仅将其余256 MB留给整个容器的其余部分。该内存将需要由容器中运行的所有其他进程以及JVM Metaspace / PermGen等分配共享。在这种情况下,也许50%不太安全。
因此,我提一下几点建议:
这超出了本文的范围,但请放心,也可以对此进行调整,但可能不应该这样做。默认的JVM行为适用于大多数用例。如果您发现自己试图解决一个晦涩的内存问题,那么可能是时候考虑摆弄JVM内存这个有些深奥的领域了,但是否则我将避免直接做任何事情。
这里没什么可做的。从Java 8u191开始,JVM默认情况下是“容器感知”的,并且可以正确解释CPU份额分配。尽管有一些细节值得我们理解,所以除了在这里概述之外,我将指导您阅读这篇出色的文章,详细说明所有这些。
现代Java非常适合在容器环境中运行,但是每个人都应该知道一些不太明显的细节,以确保他们从应用程序中获得最佳性能。我希望这里提供的信息以及出色的参考资料可以帮助您实现这一目标。