Spring Boot CDS 支持和 Project Leyden 展望

工程 | Sébastien Deleuze | 2024 年 8 月 29 日 | ...

Spring Boot 开发者如何在约束最少的情况下提高其应用程序的运行时效率,以便在大多数应用程序中享受这些好处?答案是 Spring Boot 3.3 引入的 CDS 支持,它可以让您的 Spring Boot 应用程序启动更快并消耗更少的内存。它是基于我在几个月前介绍过的 Spring Framework 6.1 引入的基础之上构建的。

关键在于,与 GraalVM 本机镜像支持 相比,新的 CDS 支持提供了不同的价值主张:通过 CDS 获得的改进,例如在启动时间方面,虽然不如本机镜像那样显著,但仍然非常重要,同时您可以继续使用常规 JVM,且副作用很少。

Spring Boot 以生产就绪的方式支持 CDS 和 GraalVM 本机镜像,并根据您的具体情况和偏好提供选择。

CDS,JVM 中的隐藏瑰宝

CDS 代表 类数据共享 (Class Data Sharing),这是一项成熟的技术,已在大多数 JVM 中可用和使用,但迄今为止尚未充分发挥其潜力。简单来说,您可能已经在不知不觉中使用了 CDS,但仅限于优化 JDK 类的加载,而您的应用程序或库中的类可能并未利用它。要解锁这一点,需要对您的应用程序执行一次训练运行。

您还需要满足一组约束条件,如果没有像 Spring Boot 这样的专用支持,这些约束很容易被打破

  • 必须使用完全相同的 JVM。
  • Classpath 必须指定为 JAR 列表,并避免使用目录、* 通配符和嵌套 JAR。
  • 必须保留 JAR 的时间戳。
  • 在生产运行时使用 CDS 归档时,classpath 必须与创建归档时使用的 classpath 相同,且顺序一致。可以在末尾指定额外的 JAR 或目录(但这些不会被缓存)。

Spring Boot 3.3 通过提供两项新功能释放了这一潜力:自解压可执行 JARBuildpacks CDS 支持

自解压可执行 JAR

直接使用可执行 JAR 运行 java -jar my-app.jar 并不是在生产环境中运行应用程序最有效的方式。这一点在文档中有所说明,但根据我与 Spring 社区的各种讨论,大多数不使用 Buildpacks 的开发者和运维人员会忽略这一点。而且直到最近,还没有真正的一流功能来提供帮助。

Spring Boot 3.3 改变了这一点,引入了可执行 JAR 无需任何外部工具即可自解压的能力,只需使用通常已用于运行应用程序的 java 命令即可

java -Djarmode=tools -jar my-app.jar extract --destination application

CDS file layout

然后您可以使用以下命令更高效地运行 Spring Boot 应用程序

java -jar application/my-app.jar

这项功能有一个超级能力:它被设计用于满足 CDS(以及 Project Leyden)的约束。因此,结合 Spring Framework 对 CDS 训练运行的支持,您可以按如下方式为您的 Spring Boot 应用程序创建 CDS 归档

java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application/my-app.jar

然后您可以使用 CDS 启用方式启动您的应用程序

java -XX:SharedArchiveFile=application.jsa -jar application/my-app.jar

Buildpacks 中的 CDS 和 Spring AOT 激活支持

自解压可执行 JAR 功能结合 CDS 使用具有灵活性,但仍需要相当多的手动步骤,因此 Spring Boot 和 Buildpacks 为 CDS 提供了集成支持,它能够

  • 在创建容器镜像时自动执行训练运行。
  • 将 Spring Boot 可执行 JAR 解压到上述 CDS 友好的文件布局中。
  • 在容器内附带 CDS 归档。
  • 运行容器镜像时自动启用 CDS。

Buildpacks CDS support

https://github.com/sdeleuze/spring-boot-cds-demo 仓库中所示,可以使用 Gradle 按如下方式启用

tasks.named("bootBuildImage") {
	environment["BP_JVM_CDS_ENABLED"] = "true"
}

或者使用 Maven

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
		<image>
			<env>
				<BP_JVM_CDS_ENABLED>true</BP_JVM_CDS_ENABLED>
			</env>
		</image>
	</configuration>
</plugin>

在训练运行期间,Spring bean 在不启动 Spring 生命周期的情况下被实例化,因此实际上您可能观察到的主要副作用是过早的数据库交互,这可以通过配置您的应用程序(或者仅通过 CDS_TRAINING_JAVA_TOOL_OPTIONS 环境变量配置训练运行)来避免,以防止此类数据库交互,如此处所述。

也可以使用 BP_SPRING_AOT_ENABLED 环境变量触发 Spring AOT 激活支持,但请务必记住以下约束

  • 在您的 Maven 或 Gradle 构建中启用 Spring AOT。
  • 可能需要配置 Spring AOT 以使用将在部署环境中的 Spring profile。
  • CDS_TRAINING_JAVA_TOOL_OPTIONSBP_SPRING_AOT_ENABLED 不能同时使用。

Broadcom 的 Spring 和 Buildpacks 团队一直在密切合作,利用这些开源特性并将其与额外的 Tanzu Platform 能力结合,以便为 Cloud Foundry 或 Kubernetes 提供一流的 CDS 支持,例如允许训练运行自动配置,使 CDS 像一个标志一样易于启用且没有副作用,并且正在开发更多平台级能力。

数据点

对于在 MacBook M2 上运行的最小 Spring MVC Tomcat 应用程序,我们观察到,与运行可执行 JAR 相比,解压后的应用程序结合 CDS 可以将启动速度加快约 1.5 倍,并将内存消耗降低 16%。如果再加入 Spring AOT,启动速度将加快约 2 倍,内存消耗将降低 27%。

WebMVC process startup time (ms) and RSS after startup (Mb)

我们看到 Petclinic 也有类似的改进。

Petclinic process startup time (ms) and RSS after startup (Mb)

这些数值在性能较低的云实例上显然会发生变化,但您应该能观察到类似的改进比例。

Spring Boot 与 Project Leyden

有趣的是,上述新 extract 命令使用的 CDS 友好布局也被设计用于与 Project Leyden 抢先体验版本 配合提供最优性能,后者可以被视为 CDS 的继任者,具有额外能力,可实现

  • 更快的启动速度。
  • 更小的容器镜像(通过移除 JDK 的 CDS 归档,只保留应用程序的)。
  • 提前预热,以便在启动后获得更好的性能并更快达到峰值性能。

目前我们观察到,使用 Project Leyden 的 Spring Boot 应用程序启动速度加快约 3 倍,结合 Project Leyden 和 Spring AOT 时启动速度加快约 4 倍。

Project Leyden data points

我将在即将到来的 Devoxx Belgium 2024 上的 Project Leyden 演讲 中分享更多内容,我很荣幸能与来自 Java 平台团队的 Per Minborg 共同进行演讲。

获取 Spring 通讯

订阅 Spring 通讯,保持联系

订阅

领先一步

VMware 提供培训和认证,助您快速前进。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅即可提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部