0


Springboot 3 高性能优化:AOT + GraalVM

1. 什么是 AOT 编译

预先 (AOT) 编译是在应用程序运行之前将高级编程语言编译为本机机器代码的过程。与在运行时动态进行的即时 (JIT) 编译不同,AOT 编译会预先将代码转换为可执行文件或二进制形式。此方法对性能有重大影响,包括启动时间更快、内存使用量减少以及总体运行时效率提高。

在 Java 和 Spring Boot 等框架的环境中,AOT 编译尤其有益。它允许应用程序更快地启动并消耗更少的资源,这在需要快速扩展或资源有限的环境中至关重要,例如云原生应用程序或 IoT 设备。AOT 编译通过消除即时编译器在运行时处理高级代码的需求来实现这些好处,从而减少了计算开销。

GraalVM原生映像是独立的可执行文件,可以通过提前处理编译的Java应用程序来生成。本机映像通常比JVM映像占用的内存更小,启动速度更快。

GraalVM 是实现 Java 应用程序 AOT 编译的关键工具之一。GraalVM 不仅提供了用于执行 Java 应用程序的运行时环境,还提供了将 Java 代码直接编译为本机可执行文件的功能,从而扩展了传统 Java 虚拟机 (JVM) 的功能。这些可执行文件是平台特定的,不需要 JVM 即可运行,这进一步减少了应用程序的资源占用。

GraalVM 对 AOT 编译的支持还使其能够执行以多种语言编写的代码,从而促进多语言应用程序的创建。此功能在微服务架构中特别有用,因为不同的服务可能用不同的语言编写,但需要编译成统一的可执行格式才能部署。

此外,Spring Boot 等框架已开始将 AOT 编译功能直接集成到其工具链中,为开发人员提供了将其应用程序编译为原生镜像的简化路径。这种集成通过利用 AOT 编译的优势简化了开发高性能、高效应用程序的过程。

2. 为什么你可能想要编译为本机

通过 GraalVM 的预先 (AOT) 编译等技术将应用程序编译为本机二进制文件具有诸多优势,可以显著提高应用程序的性能和安全性。下面详细介绍了您可能希望将应用程序编译为本机代码的原因,重点关注您列出的几点:

2.2. 即时启动

原生编译可使应用程序几乎立即启动。这是因为应用程序代码已编译为机器代码,CPU 可以直接执行,而无需字节码解释或即时 (JIT) 编译的开销。即时启动在需要快速扩展的环境中尤其有价值,例如云原生应用程序或微服务,这些环境中需要根据需求快速启动或关闭服务。

2.3 无需预热

编译为本机代码的应用程序消除了通常与 JIT 编译相关的“预热”时间。在传统的 JVM 环境中,应用程序在启动时通常运行较慢,并随着 JIT 编译器随着时间的推移优化字节码而逐渐达到其峰值性能。本机二进制文件从启动的那一刻起就以最佳性能运行,确保一致且可预测的行为,这对于性能敏感的应用程序至关重要。

2.4 低资源

占用率 与 JVM 版本相比,本机二进制文件往往具有较低的内存占用和较低的 CPU 使用率。这是因为它们不需要在运行时加载整个 JVM 或相关的类库。较低的资源占用率意味着能够在同一硬件上运行更多应用程序实例或在资源受限的设备上运行应用程序,这也使其成为一种环保的选择。

2.5 减少攻击面

编译为本机代码可以潜在地减少应用程序的攻击面。通过消除对 JVM 的需求,并控制使用反射,可以显著缩小攻击面。此方法意味着仅构建所需的组件,并且严格监督反射的使用方式,从而减少攻击者发现漏洞的机会。它简化了应用程序,使其更难受到不必要的访问或攻击,直接符合减少攻击面的目标。

2.6 紧凑型打包

本机应用程序可以仅使用执行所需的必要运行时组件进行打包,从而减小应用程序大小。这种紧凑型打包对分布式应用程序非常有利,因为它减少了在网络或互联网上部署或更新应用程序所需的时间和带宽。它还通过减小容器镜像的大小来简化容器化。

2.7 降低计算成本

即时启动、无需预热、低资源使用率和紧凑封装等特性的组合可以显著降低计算成本,尤其是在根据使用量计费的云环境中。通过优化资源消耗,编译为本机代码的应用程序可以帮助组织降低运营成本。这对于需求波动的应用程序尤其有利,因为能够在不产生不必要成本的情况下快速扩大或缩小规模的能力非常有价值。

3. 原生印象的 Usacase

3.1 应用用例

3.1.1 低内存和 CPU 环境

在内存和 CPU 资源有限的环境中,例如嵌入式系统或 IoT 设备,原生映像具有无价的价值。它们通过最大限度地减少资源占用来确保应用程序高效运行。例如,IoT 设备上监控工具的原生映像可使其以最佳状态运行,使用最少的资源,同时提供实时数据分析。

3.1.2 功能即服务 (FaaS)

无服务器计算模型(其中函数响应事件而执行)极大地受益于原生镜像。原生镜像的启动时间更短,资源需求更低,这意味着函数可以快速初始化和终止,从而优化资源使用和成本。例如,编译为原生镜像的云函数可以比传统函数更快、更经济高效地处理将图像上传到存储桶的操作。

3.1.3 规模归零

服务能够缩减到零(在需要时才消耗资源)是高效云原生架构的标志。原生镜像通过允许服务在需求出现时立即启动来促进这一点,使其成为波动工作负载的理想选择。电子商务网站的推荐服务可能会在非高峰时段缩减到零,当客户流量增加时立即启动。

3.1.4 CLI 工具

命令行界面 (CLI) 工具受益于原生镜像提供的快速启动时间和执行效率。例如,用于管理云资源的 CLI 工具在编译为原生镜像时可提供即时反馈和操作功能。这不仅提高了开发人员的工作效率,还提高了运营灵活性。使用 Spring Shell 可以实现此类改进。

3.2 建筑用例

3.2.1 微服务

微服务架构将应用程序分解为更小、可独立部署的服务,原生映像具有显著优势。这些二进制文件减少了每个微服务的启动时间和运营开销,有助于快速扩展和部署周期。例如,支付处理微服务的原生映像使其能够高效处理交易高峰,并根据需要快速扩展。

3.2.2 容器镜像分发

原生镜像与容器化部署非常契合,可提供更小的镜像大小,从而减少存储并加快分发速度。这使得在容器化环境中部署和扩展应用程序更加高效。容器化分析应用程序在构建为原生镜像时,可以快速部署到集群中,从而增强数据处理能力。

3.2.3 Kubernetes

在 Kubernetes 环境中,容器化应用程序的编排受益于原生镜像的特性。其最小的资源消耗和快速启动提高了 Kubernetes 有效管理工作负载的能力,从而实现了更灵敏的扩展和资源优化。例如,Kubernetes 集群中基于原生镜像的日志记录服务可以快速扩展以满足动态变化的工作负载的日志记录需求。

3.2.4 后台办公室

支持业务运营的后台应用程序(如库存管理或客户关系管理系统)也将受益。将这些应用程序编译为原生映像可以提高性能和可靠性,从而更有效地支持业务运营。例如,基于原生映像的库存管理工具可以提供更快的数据处理速度,从而提高供应链效率。

4. 使用原生映像时的权衡

让我们通过实际示例说明在 **Java Spring Boot **应用程序中使用 GraalVM 原生镜像的利弊。

4.1 编译时间

想象一下,Spring Boot 微服务是微服务架构的一部分,需要频繁更新。使用 GraalVM 创建本机映像的编译时间较长,可能会减慢持续部署过程。如果微服务在 JVM 设置中通常需要几秒钟才能编译,那么迁移到 GraalVM 可能会将编译时间延长到几分钟,从而影响开发周期的敏捷性。

4.2 编译期间的内存消耗

一家在有限预算下开发 Spring Boot 应用程序的初创公司可能会使用适中的云实例或较旧的硬件进行开发和构建。编译为本机映像的高内存要求可能会超出其现有设置的能力,迫使他们选择硬件升级或因交换和其他内存管理问题而面临构建过程变慢的问题。

4.3 动态功能限制

Spring Boot 应用程序严重依赖运行时反射来根据客户配置动态加载插件。使用 GraalVM 的原生镜像,开发人员需要在编译时预测所有可能的路径和配置,从而显著改变应用程序的架构或通过显式配置实现解决方法,这可能会带来维护复杂性。

4.4 兼容性和库支持

一个电子商务 Spring Boot 应用程序使用第三方库进行支付处理,该库与 GraalVM 的原生编译不完全兼容。因此,开发团队必须找到支持原生镜像的替代库,为现有库做出贡献以添加支持,或者删除该功能,从而影响产品功能。

4.5 调试和分析

财务分析 Spring Boot 应用程序在高负载下表现异常,需要进行分析以确定性能瓶颈。开发人员习惯用于 JVM 的工具和技术可能不适用于本机映像或提供较少的洞察力,需要学习曲线和可能的新工具来有效地诊断和解决问题。

4.6 运行时行为差异

专为 IoT 设备设计的 Spring Boot 应用程序会收集数据并将其发送到中央服务器。转换为原生映像后,开发人员会注意到垃圾收集行为的变化,而这些变化在基于 JVM 的测试中并不明显,从而导致某些情况下出现意外暂停或内存问题。这种情况需要进行额外的测试和优化,以确保应用程序作为原生映像顺利运行。

5. 使用 GraalVM 增强 Spring Boot 应用程序

所有示例代码均可在此存储库中找到。

5.1 使用 Building Native Image 构建工具

在本部分中,我们将探讨 Native Build Tools 插件的作用,这些插件对于将 Spring Boot 应用程序编译为本机可执行文件至关重要,尤其是在主动开发的动态阶段。

下面概述了使用 SDKMAN 的 Linux 和 Mac 平台上用户的建议安装程序:

  1. 安装 SDKMANcurl -s “https://get.sdkman.io" | bash source “/home/eduk8s/.sdkman/bin/sdkman-init.sh” sdk 列表 java
  2. 列出所有 Java 发行版。有多种选择,但建议在“GraalVM CE”(CE 代表社区版)或“Liberica NIK”(NIK 代表 Native Image Kit)之间进行选择
  3. 安装 GraalVMsdk install java 23.r17-nik java -version native-image — version
  4. 编译应用程序cd native-demo-app./gradlew nativeCompile
  5. 运行应用程序build/native/nativeCompile/native-demo-app

5.2 使用 Cloud Native Buildpack

让我们进一步讨论与云部署相关的注意事项。在本节中,我们将采用一种与云部署策略更一致的不同构建方法。

5.2.1 是什么以及为什么?

Spring Boot 可以轻松使用Cloud Native BuildpacksCloud Native Buildpacks创建容器映像。 以这种方式构建应用程序时,您将获得一个本机可执行文件和一个 Docker 容器,或者确切地说是一个 OCI 容器。 这使您的应用可以在大多数云平台上运行,例如 AWS、Azure、GCP 和 Tanzu。

5.2.2 如何部署?

在深入研究本机编译之前,让我们简要了解一下 Spring Boot 应用程序通常是如何部署的。首先,Java 源代码被转换成 Java 字节码。然后,使用 Buildpacks 将其打包成一个容器镜像,其中包含三个关键部分:操作系统层、JVM 层和应用程序本身的层。

Spring Boot 3 带来了新功能,有助于创建更小、更高效的容器镜像,通过两个额外的步骤实现。

Spring Framework 6 引入了使用预先 (AOT) 优化的功能。此过程在构建时确定要注入哪些 bean,从而减少所需的运行时反射。这使得 Spring Boot 应用更易于 GraalVM 原生镜像编译器进行分析。

在生成 Java 字节码之后,GraalVM 原生映像编译器会对应用进行静态分析。然后,它会创建一个优化的独立原生可执行文件。此可执行文件可以在最小操作系统上运行,并部署为紧凑、高效的容器映像,从而无需安装 JVM。

5.2.3 Cloud Native Buildpack 的要求

要使用 Cloud Native Buildpack 构建应用程序,您不需要在计算机上安装 GraalVM 原生镜像编译器。但是,您必须安装并设置 Docker,以便当前用户(非 root 用户)可以使用它。

5.2.4 使用 Cloud Native Buildpack 构建并运行

  1. 构建cd native-demo-app ./gradlew bootBuildImage
  2. 运行docker run — rm -p 8080:8080 docker.io/library/native-demo-app:0.0.1-SNAPSHOT

上面解释的命令执行以下操作:

  • docker运行告诉docker使用您构建的镜像启动一个容器。
  • --rm要求Docker在容器停止后将其删除,保持整洁。
  • -p8080:8080将本地计算机的端口8080映射到容器的端口8080,允许您从计算机访问容器内运行的应用程序。
  • docker.io/library/native demo-app:0.0.1-SNAPSHOT这是在前面的步骤中存储在本地docker注册表中的特定映像名称。

5.3 编码演练

使用 Java 21、Spring Boot 3 和 Gradle 8.7 构建的 native-demo-app 与 Java 21 的任何 GraalVM 发行版兼容。

Dependencies

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.4'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'org.graalvm.buildtools.native' version '0.9.28'
}

group = 'dev.native.app'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '21'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

build.gradle

文件是一个配置脚本,用于使用流行的构建自动化工具 Gradle 设置 Java 项目。它指定如何构建和测试 Native-demo-app,它使用 Spring Boot 并准备使用 GraalVM 编译成原生映像。以下是其主要组件的细分:

  • java插件:这些插件扩展了 Gradle 的功能。该文件包括Java 项目的基本插件、org.springframework.boot用于集成 Spring Boot(版本 3.2.4)、io.spring.dependency-management用于管理依赖项(版本 1.1.4)和org.graalvm.buildtools.native用于原生镜像支持的(版本 0.9.28)。
  • 组和版本:这些设置指定项目的组 ID ( dev.native.app) 和版本 ( 0.0.1-SNAPSHOT)。这些对于识别存储库中的项目工件很重要。
  • Java版本:设置sourceCompatibility为Java 21,表示项目兼容的Java源代码版本。
  • 存储库:该项目将从最大的 Java 库集合之一 Maven Central 下载其依赖项。
  • 依赖项:该dependencies块列出了项目所需的库。org.springframework.boot:spring-boot-starter-web包含使用 Spring Boot 进行 Web 应用程序开发,以及org.springframework.boot:spring-boot-starter-test使用 Spring 的测试支持测试应用程序。
  • 测试配置:该tasks.named('test')块配置测试框架以使用 JUnit 平台,这是在 JVM 上启动测试框架的基础。

6. 总结

6.1 AOT 编译优势

  • 在运行之前将代码转换为本机机器代码。
  • 通过更快的启动和减少内存使用来提高性能。
  • 对 Java 和 Spring Boot 应用程序特别有益。

6.2 编译为本机代码的优点

  • 即时应用程序启动。
  • 不需要 JIT 编译典型的预热期。
  • 降低内存占用和 CPU 使用率。
  • 由于运行时组件较少,攻击面也减少了。
  • 应用程序规模更小,计算成本更低。

6.3 原生镜像的使用案例

6.3.1 应用用例

  • 最适合低内存和 CPU 环境,如物联网设备。
  • 非常适合具有快速可扩展性的函数即服务 (FaaS)。
  • 支持缩放至零的功能,以高效利用资源。

6.3.2 建筑用例

  • 通过快速启动增强微服务架构。
  • 简化容器镜像分发和 Kubernetes 编排。
  • 适用于需要性能和可靠性的后台应用程序。

6.4 使用 GraalVM 原生镜像时的权衡

  • 编译时间更长。
  • 编译期间增加了内存要求。
  • 对动态功能的限制和潜在的库兼容性问题。
  • 在开发和部署阶段需要仔细考虑。

6.5 使用云原生 Buildpacks 进行构建

  • 简化容器镜像创建,无需本地安装 GraalVM。
  • 需要安装 Docker 来构建和运行应用程序。
  • 与云部署策略保持一致,易于在云平台上部署。

6.6 开发工作流程

  • 利用“build.gradle”文件设置项目,包括 Java、Spring Boot 和 GraalVM 插件。
  • 指定使用 Java 21 实现源兼容性,从而利用最新的 Java 功能。
  • 包括使用 Spring Boot 进行 Web 开发和测试的依赖项。

6.7 重点

  • Spring Boot 3 与 AOT 编译和 GraalVM 原生镜像的集成为开发高效、高性能应用程序提供了一种强大的方法,满足了应用程序开发和部署的现代需求,尤其是在云原生环境中。

本文转载自: https://blog.csdn.net/lilinhai548/article/details/141442835
版权归原作者 龙殿殿主 所有, 如有侵权,请联系我们删除。

“Springboot 3 高性能优化:AOT + GraalVM”的评论:

还没有评论