如何解决用于构建 spring-boot 应用程序的 Paketo buildpack 的内存问题?

How to solve Memory issues with Paketo buildpack used to build a spring-boot app?

我正在使用部署到 AWS BeanStalk 的 spring-boot-maven-plugin 构建 Docker 映像。我通过 2.4.3 spring boot starter 依赖使用插件) 但是,当容器启动时,出现以下错误。 我对 buildpack 的东西有点陌生,但试图通过使用网站上描述的 Buildpack env 变量来解决它。但它对下面错误日志中显示的值绝对没有影响。 我找到了这个 github issue 但不确定它是否相关以及如何使用它。

我正在使用 AWS Micro 实例,总内存为 1G,它执行滚动更新,因此在启动新映像时,另一个也在 运行ning 直到新映像成功启动,因此启动容器也可能只有 300MB 可用,但是,在正常 运行 期间它有更多可用空间。

为什么我需要这个内存计算?我不能禁用它吗?当我构建 app.jar 的 Docker 图像并将其部署到 aws beanstalk 时,它在没有任何内存设置的情况下运行良好:

docker build . --build-arg JAR_FILE=./target/app.jar -t $APPLICATION_NAME

但我很想使用通过 spring-boot-maven 插件构建的图像。 请就如何解决这个问题提出一些建议?

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <image>
                    <name>${image.name}</name>
                    <env>
                        <tag>${project.version}</tag>
                        <!--BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:MaxDirectMemorySize=1M</BPE_APPEND_JAVA_TOOL_OPTIONS-->
                        <BPE_JAVA_TOOL_OPTIONS>-Xms1024m -Xmx3048m</BPE_JAVA_TOOL_OPTIONS>
                    </env>
                </image>
            </configuration>
        </plugin>

部署期间的 AWS Beanstalk 错误:

Tue May 18 2021 18:07:14 GMT+0000 (UTC)   INFO   Successfully built aws_beanstalk/staging-app
Tue May 18 2021 18:07:22 GMT+0000 (UTC)   ERROR   Docker container quit unexpectedly after launch: 0M, -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. Check snapshot logs for details.
Tue May 18 2021 18:07:24 GMT+0000 (UTC)   ERROR   [Instance: i-0dc33dcb517e89ef9] Command failed on instance. Return code: 1 Output: (TRUNCATED)...pectedly after launch: 0M, -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. Check snapshot logs for details. 
Hook /opt/elasticbeanstalk/hooks/appdeploy/enact/00run.sh failed. For more detail, check /var/log/eb-activity.log using console or EB CLI.
Tue May 18 2021 18:07:24 GMT+0000 (UTC)   INFO   Command execution completed on all instances. Summary: [Successful: 0, Failed: 1].
Tue May 18 2021 18:07:24 GMT+0000 (UTC)   ERROR   Unsuccessful command execution on instance id(s) 'i-0dc33dcb517e89ef9'. Aborting the operation.
Tue May 18 2021 18:07:24 GMT+0000 (UTC)   ERROR   Failed to deploy application.
Tue May 18 2021 18:07:24 GMT+0000 (UTC)   ERROR   During an aborted deployment, some instances may have deployed the new application version. To ensure all instances are running the same version, re-deploy the appropriate application version.
##[error]Error: Error deploy application version to Elastic Beanstalk

在 AWS Beanstalk 中下载的 Docker 错误日志:

Docker container quit unexpectedly on Tue May 18 18:07:21 UTC 2021:
Setting Active Processor Count to 1
Calculating JVM memory based on 274300K available memory
unable to calculate memory configuration
fixed memory regions require 662096K which is greater than 274300K available for allocation: -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=150096K, -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

好的,这就是告诉我们的内容:

Calculating JVM memory based on 274300K available memory

内存计算器检测到容器中可用的最大内存量为 274300KB,或大约 274M。

fixed memory regions require 662096K which is greater than 274300K available for allocation: -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=150096K, -XX:ReservedCodeCacheSize=240M, -Xss1M * 250 threads

这条消息是说内存计算器在当前配置下至少需要 662096KB 或 662M。

它也打破了为什么它 needs/wants 这么多:

  • 直接内存10M
  • 元空间 150096K
  • 240M 预留代码缓存
  • 线程 250M(特别是线程堆栈)

这还不包括需要更多空间的堆(您似乎至少需要 1G 的堆空间)。

这留下了两种可能性:

  1. 容器没有提供足够大的空间。你需要给它更多的内存。
  2. 内存计算器未正确检测到内存限制。

如果您怀疑#2,请查看以下内容。内存计算器通过按此顺序查看这些位置来选择它的最大内存限制(即上例中的 274M)。

  1. 通过查看容器内部的 /sys/fs/cgroup/memory/memory.limit_in_bytes 检查配置的容器内存限制。
  2. 再次从容器内部查看 /proc/meminfoMemAvailable 指标,检查系统的最大可用内存。
  3. 如果所有其他方法都失败了,它将以 1G 回退结束。

如果它确实没有如上所述工作,please open a bug并提供尽可能多的细节。


或者,您可以调整内存计算器。您可以指示它为特定区域提供更少的内存,以便将所需的总内存减少到小于最大可用内存。

您可以通过在 JAVA_TOOL_OPTIONS 环境变量中设置 JVM 内存标志来做到这一点(您有 BPE_JAVA_TOOL_OPTIONS,这是不对的)。参见 https://paketo.io/docs/buildpacks/language-family-buildpacks/java/#runtime-jvm-configuration

例如,如果您想覆盖堆大小,则将 JAVA_TOOL_OPTIONS 中的 -Xmx 设置为自定义值。内存计算器将查看您的设置并相应地调整剩余内存设置。根据需要重写。

要将内容缩小到 274M 内存以内,您必须非常小。类似于 -Xss256K -XX:ReservedCodeCacheSize=64M -XX:MaxMetaspaceSize=64 -Xmx64M。我没有测试确认,但这显示了你需要做什么的想法。减少内存设置,使总和符合容器的最大内存限制。

这也没有考虑您的应用程序是否真的能够 运行 在如此小的限制内。如果设置得太小,有时您可能会看到 OutOfMemoryErrors 或 WhosebugErrors,然后您的应用程序就会崩溃。您还可以通过过多地减少代码缓存大小来对性能产生负面影响,因为这是 JIT 存储字节码的地方,它已针对本机代码进行了优化。如果堆的大小不正确,您甚至可能会导致 GC 问题,或者由于过多的 GC 而导致性能下降。简而言之,如果您要这样做,请务必小心。