AppCDS

本参考指南解释如何在 Quarkus 应用程序中启用应用程序类数据共享。

This reference guide explains how to enable Application Class Data Sharing in your Quarkus applications.

What is Application Class Data Sharing (AppCDS)?

Application Class Data Sharing 是一项 JVM 功能,它有助于减少 JVM 应用程序的启动时间和内存占用。这是通过让 JVM 创建一个预处理过的类共享存档来实现的,该存档在启动时加载。由于这些类在应用程序每次启动时都会加载,因此 AppCDS 是一种在无需对应用程序进行特定方式的编码或配置的情况下从概念上改善应用程序启动时间的简单方法。改善程度取决于许多因素,例如加载的类数量、底层硬件等。

Application Class Data Sharing is a JVM feature that helps reduce the startup time and memory footprint of a JVM application. This is achieved by having the JVM create a pre-processed shared archived of classes that are loaded at startup time. As these classes are loaded every time the application starts, AppCDS is a conceptually simple way of improving the application startup time, without the application itself having to be coded or configured in a specific way. How much of an improvement depends on many factors, such as the number of classes loaded, the underlying hardware etc.

Vanilla AppCDS generation

为应用程序手动创建 AppCDS 的主要缺点是,它们的生成需要使用特殊标志启动应用程序,并在应用程序部署到生产环境之前的步骤中获取存档。

The main downside of creating AppCDS manually for an application is that their generation requires launching the application with special flags and obtaining the archive in a step before the application is deployed to production.

确切的过程取决于所使用的 JVM 版本,因为较新的 JVM 逐渐使该过程变得更容易。

The exact process depends on the JVM version being used as newer JVM have incrementally made the process easier.

这一事实使得 AppCDS 在 CI 管道负责构建和部署应用程序的实际部署中难以使用。

This fact makes the use of AppCDS difficult to use for real world deployments where a CI pipeline is responsible for building and deploying applications.

AppCDS in Quarkus

Creating the archive

Quarkus 使 AppCDS 生成变得像设置 quarkus.package.jar.appcds.enabled 配置属性为 true 一样简单。对于使用 Maven 的示例 Quarkus 应用程序(假设它位于 /tmp/code-with-quarkus),可以通过像这样构建应用程序来生成 AppCDS 存档:

Quarkus makes AppCDS generation as simple as setting the quarkus.package.jar.appcds.enabled configuration property to true. For an example Quarkus application using Maven (assuming it is located in /tmp/code-with-quarkus), the AppCDS archive can be generated by simply building the application like so:

./mvnw package -Dquarkus.package.jar.appcds.enabled=true

当构建完成后,输出将包含以下内容(除其他内容外):

When the build completes, the output will contain (among other things) the following:

[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] Launching AppCDS creation process.
[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] AppCDS successfully created at: '/tmp/code-with-quarkus/target/quarkus-app/app-cds.jsa'.
[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] To ensure they are loaded properly, run the application jar from its directory and also add the '-XX:SharedArchiveFile=app-cds.jsa' JVM flag.
Moreover, make sure to use the exact same Java version (x.y.z) to run the application as was used to build it.

如果我们查看 /tmp/code-with-quarkus/target/quarkus-app,除了其他文件外,我们看到 app-cds.jsa,这是生成的 AppCDS 存档。

If we take a look at /tmp/code-with-quarkus/target/quarkus-app, among the other files, we see app-cds.jsa, which is the generated AppCDS archive.

Using the archive

使用存档的方法是使用 -XX:SharedArchiveFile 标志。但是,一些注意事项适用:

Using the archive is done by using the -XX:SharedArchiveFile flag. However, a few caveats apply:

  • The paths to the Quarkus jar file and the AppCDS archive need to be exactly the same as those Quarkus used to build the archive

  • The version of the JVM used to run the application must be exactly the same as the one used to build the Quarkus application.

假设我们使用与构建应用程序相同的 JVM 来运行应用程序,我们可以像这样启动应用程序:

Assuming we are using the same JVM to run the application as we used to build the application, we can launch the application like so:

cd target/quarkus-app
java -XX:SharedArchiveFile=app-cds.jsa -jar quarkus-run.jar

JVM 具有弹性。在存档文件不可用(无论出于何种原因)的情况下,它只会禁用 AppCDS 功能。

The JVM is resilient. Faced with a situation where the archive file is not usable (for whatever reason) it will simply disable the AppCDS feature.

如果希望在归档不可用时简单地停止执行,可以使用以下命令行调用:

If it is desirable to simply halt the execution when the archive is not usable, the following command line invocation can be used:

java -Xshare:on -XX:SharedArchiveFile=app-cds.jsa -jar quarkus-run.jar

考虑到上面提到的有关如何启动应用程序才能构建归档的信息, возникает вопрос о том, как Quarkus 处理这种情况。

Given what was mentioned above about how the application needs to be launched in order for the archive to be built, the question arises of how Quarkus deals with this situation.

答案是在应用程序构建时,在应用程序归档构建完毕后,Quarkus 立即启动应用程序,但仅运行启动过程的那些安全部分。更具体地说,该应用程序一直运行到实际打开套接字或运行应用程序逻辑的步骤。

The answer is that at application build time, right after the application archive is built, Quarkus launches the application, but only the parts of the launch process that are safe are run. More specifically, the application is run up until the steps that actually open sockets or run application logic.

这将产生一个一方面完全安全的存档生成流程,但另一方面又无法归档应用程序在启动时可能需要的每个单独类。因此,如果用户手动执行生成 AppCDS 存档的环节,他们可以获得效果略佳的存档。

This results in an archive generation process that on one hand is completely safe, but on the other hand is unable to archive every single class that the application might need at boot time. As a result, users are expected to get a slightly more effective archive if they manually go through the hoops of generating the AppCDS archive.

AppCDS 在最新的 JDK 版本中得到了显著的改进。这意味着,要确保从中获得最佳的改进,请确保您的项目针对最高可能的 Java 版本(理想情况下为 17 或 21)。

AppCDS has improved significantly in the latest JDK releases. This means that to ensure the best possible improvements from it, make sure your projects targets the highest possible Java version (ideally 17 or 21).

Usage in containers

在使用 quarkus-container-image-jib 扩展构建容器映像时,Quarkus 会自动处理生成该存档所需的全部步骤,并使该存档可在容器的运行时使用。

When building container images using the quarkus-container-image-jib extension, Quarkus automatically takes care of all the steps needed to generate the archive and make it usable at runtime in the container.

通过这种方式,只需将 quarkus.package.jar.appcds.enabled 设置为 true ,生成的容器即可减少启动时间和内存使用率。

This way, by simply setting quarkus.package.jar.appcds.enabled to true the generated container can benefit from a slight reduction in startup time and memory usage.