当前位置: 首页 > 知识库问答 >
问题:

Kubernetes正在为运行JVM的豆荚腾出空间

孟佑运
2023-03-14

我正在运行包含JVM(java8u31)的Docker容器。这些容器被部署为kubernetes集群中的吊舱。我经常为豆荚腾出空间,库伯内特斯杀死豆荚并重新启动。我在寻找这些OOM的根本原因时遇到了问题,因为我是库伯内特斯的新手。

>

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms700M -Xmx1000M  -XX:MaxRAM=1536M  -XX:MaxMetaspaceSize=250M 

这些容器作为有状态集部署,下面是资源分配

resources:
    requests:
        memory: "1.5G"
        cpu: 1
    limits:
        memory: "1.5G"
        cpu: 1

因此,分配给容器的总内存与MaxRam匹配

如果我使用-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/etc/opt/jmx/java_-pid%p.hprof,那就没用了,因为pod会被杀死,重新创建,一旦有OOM,就会启动,所以pod内的一切都会丢失

获得线程或HEAP转储的唯一方法是SSH到pod中,这也是我不能接受的,因为pod是在OOM之后重新创建的,所以我在OOM时没有内存占用。我SSHOOM,这没有多大帮助。

我还使用Visual alVM,jHat分析了代码,但没有找到大量的内存占用,这可能会导致JVM中运行的线程消耗太多内存或可能泄漏的结论。

感谢任何帮助解决库伯内特斯抛出的OOM。

共有3个答案

鲁羽
2023-03-14

感谢@VAS的评论。感谢kubernetes的链接。

经过几次测试后,我认为如果使用-XX:UseCGroupMemoryLimitForHeap,那么指定XMX不是一个好主意,因为XMX会覆盖它。我还在做更多的测试

因为我的需求是在docker容器中运行JVM。正如@Eugene在帖子中提到的,我做了一些测试。考虑到在JVM中运行的每个应用html" target="_blank">程序都需要堆和一些本机内存,我认为我们需要指定-XX:UnlockExperimentalVMOptions,XX:UseCGroupMemoryLimitForHeap,-XX:MaxRAMFraction=1(只考虑容器内运行的JVM,同时也有风险)-XX:MaxRAM(我认为如果MaxRAMFraction为1,我们应该指定它,以便为本机内存保留一些)

几项测试:

根据下面的docker配置,考虑到您只有JVM在容器内运行,docker被分配了1 GB。考虑到docker分配给1G,我也想分配一些给进程/本机内存,我想我应该使用MaxRam=700M,这样我就有300 MB的本机内存。

$docker run-m 1GB openjdk:8u131 java-XX:UnlockExperimentalVMOptions-XX:UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=1-XX:MaxRAM=700M-XshowSettings:vm-version vm设置:最大堆大小(估计):622.50M工效学机器类别:使用vm的服务器:openjdk 64位服务器vm

现在指定XX:MaxRAMFraction=1可能会导致死亡:

参考资料:https://twitter.com/csanchez/status/940228501222936576?lang=en-XX:MaxRAMFraction=1在集装箱环境中安全生产吗?

以下内容会更好,请注意,我已经删除了MaxRAM,因为MaxRAMFraction

$docker run-m 1GB openjdk: 8u131 java-XX: Unlock实验-VMOptions-XX: UseCGroupMemoryLimitForHeap-XX: MaxRAMFraction=2-Xshow设置: vm版本VM设置:最大堆大小(估计):455.50M人体工程学机器类:使用VM的服务器: OpenJDK 64位服务器VM

这为本机提供了500米的剩余空间,例如,可以通过指定-XX:MaxMetaspaceSize:

$docker run-m 1GB openjdk:8u131 java-XX:UnlockExperimentalVMOptions-XX:UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=2-XX:MaxMetaspaceSize=200M-XshowSettings:vm-version vm设置:最大堆大小(估计):455.50M工效学机器类别:使用vm的服务器:openjdk 64位服务器vm

从逻辑上讲,根据上述参考,指定-XX: MaxRAMFraction是有意义的

我还在做更多的测试,将更新这些结果或发布。谢谢

亢保赫
2023-03-14

如果您能够在Java 11(或10)而不是8上运行,那么内存限制选项已经得到了很大的改进(而且JVM支持cgroups)。只需使用-XX:MaxRAMPercentage(范围0.0100.0):

$ docker run -m 1GB openjdk:11 java -XshowSettings:vm -XX:MaxRAMPercentage=80 -version
VM settings:
    Max. Heap Size (Estimated): 792.69M
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Debian-2)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Debian-2, mixed mode, sharing)

这样,您就可以轻松地为堆指定80%的可用容器内存,这在旧选项中是不可能的。

都浩淼
2023-03-14

当pod中的应用程序达到资源设置的内存限制时。限制。内存或命名空间限制,库伯内特斯重新启动pod。

以下文章介绍了限制资源的库伯内特斯部分:

  • 库伯内特斯最佳实践:资源请求和限制
  • 资源配额
  • 准入控制插件:ResourceQuota
  • 为容器和Pod分配内存资源

Java应用程序消耗的内存不限于堆的大小,您可以通过指定以下选项来设置堆的大小:

-Xmssize Specifies the initial heap size.
-Xmxsize Specifies the maximum heap size.

Java应用程序需要一些额外的内存来实现元空间、类空间、堆栈大小,而JVM本身需要更多的内存来完成垃圾回收机制、JIT优化、堆外分配、JNI代码等任务。很难以合理的精度预测JVM的总内存使用量,所以最好的方法是在正常负载的实际部署中测量它。

我建议您将库伯内特斯pod限制设置为双Xmx大小,检查您是否不再获得OOM,然后逐渐减小到开始获得OOM时的点。最终值应该在这些点之间的中间。
您可以从Prometheus这样的监控系统中的内存使用统计中获得更精确的值。

另一方面,您可以通过指定可用选项的数量来限制java内存的使用,如下所示:

-Xms<heap size>[g|m|k] -Xmx<heap size>[g|m|k]
-XX:MaxMetaspaceSize=<metaspace size>[g|m|k]
-Xmn<young size>[g|m|k]
-XX:SurvivorRatio=<ratio>

更多细节可以在以下文章中找到:

  • 适当限制JVM的内存使用(Xmx还不够)

限制JVM内存使用的第二种方法是根据RAM(或MaxRAM)的数量计算堆大小。这篇文章很好地解释了它的工作原理:

默认大小基于机器上的内存量,可以使用-XX:MaxRAM=N标志进行设置。通常,JVM通过检查机器上的内存量来计算该值。但是,JVM将客户机编译器的MaxRAM限制为1 GB,32位服务器编译器限制为4 GB,64位编译器限制为128 GB。最大堆大小是最大内存的四分之一。这就是为什么默认堆大小可能会有所不同:如果机器上的物理内存小于MaxRAM,则默认堆大小为该大小的四分之一。但是,即使有数百GB的RAM可用,JVM默认使用的最大内存也是32GB:128GB的四分之一。默认的最大堆计算实际上是这样的:

Default Xmx=MaxRAM/MaxRAMFraction

因此,也可以通过调整-XX:MaxRAMFraction=N标志的值来设置默认的最大堆,该标志默认为4。最后,为了保持有趣,还可以将-XX:ErgoHeapSizeLimit=N标志设置为JVM应该使用的最大默认值。默认情况下,该值为0(意味着忽略它);否则,如果该限值小于MaxRAM/MaxRAMFraction,则使用该限值。

初始堆大小的选择是相似的,尽管它的复杂性较少。初始堆大小值是这样确定的:

Default Xms=MaxRAM/InitialRAMFraction

从默认的最小堆大小可以得出结论,InitialRAMFraction标志的默认值是64。如果该值小于5 MB,或者严格地说,小于-XX:OldSize=N(默认值为4 MB)加上-XX:NewSize=N(默认值为1 MB)指定的值,就会出现一个警告。在这种情况下,旧大小和新大小之和被用作初始堆大小。

本文为您提供了一个很好的起点,可以开始为面向web的应用程序调整JVM:

  • 您应该在生产中始终使用的Java虚拟机选项
 类似资料:
  • PostgreService.yaml 已创建服务的终结点为 然后我在pod(kubectl exec-it mark-dummy-pod bash)内运行ping172.31.6.149,但不工作。(ping localhost正在工作)

  • 如何使用命令行列出特定实例组节点中运行的所有节点? 例如,如果我有instancegroup“foo”,它有三个节点:N1、N2和N3,它们依次有在N1上运行的pods A和B,在N2上运行的pods C、D和E,在N3上运行的pods F....我如何使用Kops/Kubectl使用输入“foo”和输出“a、B、C、D、E、f”进行查询? 我知道您可以查询一个特定的节点并列出其中的所有节点,但我

  • 我们有一个应用程序,其中包含 4 个 pod,并使用负载均衡器运行!我们想尝试滚动更新,但我们不确定当 Pod 出现故障时会发生什么!文档不清楚!特别是《豆荚的终止》中的这句话: Pod将从服务的endpoint列表中删除,并且不再被视为复制控制器的运行Pod集的一部分。缓慢关闭的Pod可以继续为流量提供服务,因为负载平衡器(如服务代理)将它们从轮换中删除。 因此,如果有人能在以下问题上指导我们:

  • 我希望我的pod在一段时间后(例如每周或每月)从我的部署中优雅地回收。如果我知道库伯内特斯命令,我知道我可以为此添加一个cron作业。 问题是在库伯内特斯做这件事的最好方法是什么,哪个命令会让我实现这个目标? 非常感谢你在这件事上帮助我。

  • 我在一个有3个节点的kubernetes集群上运行nginx。 我想知道是否有任何好处,例如,有4个豆荚和限制他们的CPU/MEM约。节点容量的1/4相对于每个节点运行一个pod,限制CPU/MEM,以便pod可以使用整个节点的资源(为了简单起见,我们将cubernet服务排除在等式之外)。 我的感觉是,豆荚越少,开销就越小,每个节点使用1个豆荚应该是性能最好的? 提前致谢

  • 环境*Kubernetes 1.9.3*使用在AWS(专用网络拓扑)上运行的kops(V1.8)创建的集群*网络:weave-net*集群:1主,3节点 事件实例时间线 > 我们已经使用kops执行了滚动集群更新,以使用我们构建的新AMI(基于kops AMI k8s-1.8-debian-jessie-amd64-hvm-ebs-2017-11-27)启动节点和主机。调整kops AMI从来都不