如何从 buildpack 生成的 docker 映像中禁用内存计算器

Posted

技术标签:

【中文标题】如何从 buildpack 生成的 docker 映像中禁用内存计算器【英文标题】:how to disable memory calculator from docker image generated by buildpack 【发布时间】:2022-01-07 22:38:37 【问题描述】:

当我在 deployment.yml 中为使用命令 (mvn spring-boot:build-image) 生成 docker 映像的 Spring Boot 应用程序建立内存限制 (-Xmx512m -Xms512m) 时,我收到以下错误:

Setting Active Processor Count to 4
Adding $JAVA_OPTS to $JAVA_TOOL_OPTIONS
unable to calculate memory configuration
all memory regions require 1130933K which is greater than 956052K available for allocation: 
-Xmx512M, 0 headroom, -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=94645K, -XX:ReservedCodeCacheSize=240M,
-Xss1M * 250 threads ←[31;1mERROR: ←[0mfailed to launch: exec.d: failed to execute exec.d file
at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1

当前的 deployment.yml 配置:

      env:
        - name: SPRING_PROFILES_ACTIVE
          value: prod
        - name: JAVA_OPTS
          value: >-
                -XX:+PrintGCDetails
                -Xlog:gc
                -XX:+UseParallelGC
                -XX:+PrintFlagsFinal
                -Xmx512m
                -Xms512m
      resources:
          requests:
            cpu: 1554m
            memory: 979M
          limits:
            cpu: 1554m
            memory: 979M

如何正确设置内存限制或禁用 buildpack 内存计算器?

注意:我使用的是 JAVA 11。

更新:

感谢您的回答。 但是我应用了第二个选项,我理解您的观点,我将尝试对方法进行总结

迭代 1:无限制

 env:
            - name: SPRING_PROFILES_ACTIVE
              value: prod
            - name: JAVA_OPTS
              value: >-
                    -Xlog:gc
                    -XX:+UseParallelGC

grafana visualization it1

内存计算器:

Calculating JVM memory based on 13287832K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx12681764K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 13287832K, Thread Count: 250, Loaded Class Count: 14194, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -Xlog:gc -XX:+UseParallelGC -XX:MaxDirectMemorySize=10M -Xmx12681764K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true

Xmx12681764K = 1585,2205 MB

在这种情况下,Grafana 从硬件可视化所有资源,这不是理想的配置,因此,有必要从上边界定义限制,即 Pod。

迭代 2:在 kubernetes 级别定义了限制

  env:
    - name: SPRING_PROFILES_ACTIVE
      value: prod
    - name: JAVA_OPTS
      value: >-
            -Xlog:gc
            -XX:+UseParallelGC
  resources:
    requests:
      cpu: 1554m
      memory: 979M
    limits:
      cpu: 1554m
          memory: 979M

grafana visualization it2

内存计算器:

Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx349984K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 956052K, Thread Count: 250, Loaded Class Count: 14194, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -Xlog:gc -XX:+UseParallelGC -XX:MaxDirectMemorySize=10M -Xmx349984K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enabl

在这种情况下,内存计算器会确定与应用程序一起运行的最小内存,但不限制上限,因为它受 k8s 级别的配置限制。我的疑问是由 grafana 可视化的延迟引起的。

正如您所说,内存计算器是我们的帮手。

在此先感谢

阿尔贝托。

【问题讨论】:

【参考方案1】:

你得到了错误:

all memory regions require 1130933K which is greater than 956052K available for allocation: 
-Xmx512M, 0 headroom, -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=94645K, -XX:ReservedCodeCacheSize=240M,
-Xss1M * 250 threads

这告诉您您的内存配置无效。您要分配给 JVM 的内存量不符合您对容器设置的限制。

有很多方法可以解决这个问题:

    增加容器内存限制以适应 JVM。错误消息告诉您需要多少,1130933K

    减少分配给 JVM 的内存量,使其符合容器内存限制。错误消息告诉您正在使用哪些 JVM 内存设置,您可以在JAVA_TOOL_OPTIONS(或JAVA_OPTS,其中添加的任何内容都包含在JAVA_TOOL_OPTIONS)中覆盖它们以限制它们。

    从 JAVA_OPTS 中删除 -Xmx512m -Xms512m 并让内存计算器生成最大的 JVM 内存配置,该配置将适合您分配的容器内存限制。您不会获得那么多堆,但会在给定的容器内存限制内获得尽可能大的堆。

关于这些选项的一些说明:

    如果您尝试选项 #2,请注意减少的内容。 JVM 需要大量内存,但这也是它如此之快的原因。确保在进行任何更改之前和之后进行性能测试,以确保不会影响应用程序的性能(或确认您的性能仍然达到要求的水平)。

    使用 Paketo Java buildpack,您真的不应该设置 -Xmx-Xms。相反,您要做的是调整其他内存设置,例如-Xss-XX:ReservedCodeCacheSize=240M-XX:MaxDirectMemorySize=10M、线程数等...

    内存计算器将动态调整-Xmx-Xms 设置,以便它们消耗容器中剩余的内存。如果您手动设置这些值,可能会发生错误,因为这些值太大(这里发生的情况),或者您将它们设置得太低并且 JVM 没有使用所有可用的内存.让内存计算器完成它的工作,您将获得最佳设置。

    没有禁用内存计算器的选项,我强烈警告不要尝试这样做。内存计算器是你的朋友。

    它就像一个用于 JVM 内存设置的编译器。它正在检查和验证您输入的设置,因此它可以提前告诉您内存配置是否存在问题。它抱怨可能很烦人,但这比让你的容器在半夜崩溃要好得多,因为它内存不足。如果它抱怨,请调整您的内存配置,然后放心地知道所有内容都已适当大小以适合您的容器。

    默认情况下,内存计算器会根据生产部署调整您的应用程序大小,优化性能,而不是低内存消耗。同样,Java 以更高的内存消耗换取速度。为此,这意味着您的容器至少需要 1G 的 RAM。

    内存计算器有一个Paketo RFC to add a low-memory mode。这将使运行 PoC 应用程序和其他低流量应用程序变得更容易,这些应用程序愿意接受潜在的较低性能以换取减少内存消耗(从而降低成本)。此 RFC 在本文中尚未实施,但我们希望在不久的将来实施。

【讨论】:

以上是关于如何从 buildpack 生成的 docker 映像中禁用内存计算器的主要内容,如果未能解决你的问题,请参考以下文章

使用Buildpacks高效构建Docker镜像

使用Buildpacks高效构建Docker镜像

使用云原生buildpacks将你的代码转换成Docker Image | 技术干货

在 Paketo.io / Cloud Native Buildpacks 构建的 Docker 容器中运行 Nuxt.js

Docker笔记——jdk镜像制作

如何在 Heroku 中卸载此 buildpack?