有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如何在Kubernetes中优雅而安全地最大化分配给Java应用程序的堆空间量?

我有一个Kubernetes部署,它基于anapsix/alpine-java映像部署Java应用程序。除了Java应用程序和容器开销之外,容器中没有其他运行内容

我想最大化Java进程在docker容器中可以使用的内存量,并最大限度地减少保留但从未使用的ram量

例如,我有:

  1. 两个Kubernetes节点,每个节点有8 gig的ram,并且没有交换
  2. 一种Kubernetes部署,它运行一个Java进程,最多消耗1 gig的堆来优化运行

我如何安全地最大化两个节点上运行的pod数量,而不会因为内存限制而让Kubernetes终止我的pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
    app: my-deployment
    spec:
      containers:
      - name: my-deployment
    image: myreg:5000/my-deployment:0.0.1-SNAPSHOT
    ports:
    - containerPort: 8080
      name: http
    resources:
      requests:
        memory: 1024Mi
      limits:
        memory: 1024Mi

Java8Update131+有一个标志-XX:+UseCGroupMemoryLimitForHeap使用来自Kubernetes部署的Docker限制

我的Docker实验告诉我Kubernetes发生了什么

如果我在Docker中运行以下命令:

docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version

我得到:

VM settings:
Max. Heap Size (Estimated): 228.00M

这个低值是因为Java在默认情况下将-XX:MaxRAMFraction设置为4,我得到了分配的大约1/4的ram

如果在Docker:

docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=2 -version

我得到:

VM settings:
Max. Heap Size (Estimated): 455.50M

最后,设置MaxRAMFraction=1会很快导致Kubernetes杀死我的容器

docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=1 -version

我得到:

VM settings:
Max. Heap Size (Estimated): 910.50M

共 (2) 个答案

  1. # 1 楼答案

    我认为这里的问题是kubernetes内存限制是针对容器的,而MaxRAMFraction是针对jvm的。因此,如果jvm堆与kubernetes限制相同,那么容器本身就没有足够的内存了

    你可以尝试的一件事是增加

    limits:
      memory: 2048Mi
    

    保持requests限制不变。请求和限制之间的根本区别在于,如果节点级别有可用内存,而limits是一个硬限制,则请求将允许您超过限制。这可能不是一个理想的解决方案,您必须计算出您的pod在jvm上消耗了多少内存,但是作为一个快速修复,增加limits应该可以工作

  2. # 2 楼答案

    在我们的例子中,我们所做的是在kubernetes上启动高内存限制,在负载下观察一段时间,或者将内存使用调整到我们希望通过-Xmx达到的水平,或者根据实际内存消耗调整内存限制(和请求)。说实话,我们通常混合使用这两种方法。这种方法的关键是在集群(我们的例子中是Prometheus)上启用适当的监视,如果您想要高水平的微调,您可能还需要添加类似JMX Prometheus exporter的东西,以便在调优设置时详细了解度量