Skip to content

如何实现Windows10下GraalVM本地镜像化

HaojunRen edited this page Aug 24, 2024 · 4 revisions

如何实现Windows 10下基于Java 17 + Spring Boot 3 + GraalVM本地镜像化

前言

Nepxion社区对相对简单的全链路自动化模拟流程测试和全链路自动化流量侦测测试模块尝试进行本地化,的确启动速度提升10倍甚至更多,内存占用少了1/2 ~ 2/3甚至更多,网络吞吐量也有不少提升。最终成果通过Windows 10的可执行文件EXE呈现,从下面图片可以看到,启动控制台,只耗费0.2

Nepxion社区分别对Java 8Java1 7Spring Boot 2Spring Boot 3组合场景下,对Spring Cloud Gateway、2个A服务、2个B服务做全链路自动化蓝绿灰度发布模拟流程测试,得出如下结论:

  • 全套非本地化,Spring Boot 2 + Spring Boot Cloud Hoxton + Java 8,自动化测试耗时180-200
  • 全套非本地化,Spring Boot 2 + Spring Boot Cloud Hoxton + Java 17,自动化测试耗时109-115
  • 全套非本地化,Spring Boot 3 + Spring Boot Cloud 2022 + Java 17,自动化测试耗时93-97
  • 自动化测试端本地化,网关和服务非本地化,Spring Boot 3 + Spring Boot Cloud 2022 + Java 17,自动化测试耗时80-83
  • 全套本地化,Spring Boot 3 + Spring Boot Cloud 2022 + Java 17,未测试

下面阐述一下,Windows 10操作系统下基于Java 17 + Spring Boot 3 + GraalVM实现服务本地镜像化(Native Image)的简单步骤

搭建环境

安装GraalVM

下载https://www.graalvm.org/downloads/,解压安装

安装Visual Studio

下载https://visualstudio.microsoft.com/zh-hans/downloads/,在线安装

一般选择使用 C++ 的桌面开发 -> MSVC v143 - VS 2022 C++ x64/x86 生成工具Windows 10 SDK的最新版本(Windows 11需要安装Windows 11 SDK的最新版本)即可

设置环境变量

JAVA_HOME=E:\Tool\Graalvm-JDK17-22.3.0

LIB=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\um\x64;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\ucrt\x64;E:\Tool\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\lib\x64

INCLUDE=C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\shared;E:\Tool\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include

PATH=E:\Tool\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\bin\HostX64\x64

注意:Visual Studio版本号和目录,不同的机器上有所区别,请自行更改

执行本地化

本地化插件的编写方式,请访问https://github.com/Nepxion/DiscoveryTool/blob/console-springboot-3.x.x/pom.xml,参考profile<id>native</id>部分

核心编译本地化插件

<project>    
    <!-- Only for GraalVM Native Image -->
    <profiles>
        <profile>
            <id>native</id>
            <build>
                <pluginManagement>
                    <plugins>
                        <plugin>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-maven-plugin</artifactId>
                            <version>3.0.1</version>
                            <configuration>
                                <jvmArguments>
                                    -agentlib:native-image-agent=config-merge-dir=src/main/resources/META-INF/native-image/
                                </jvmArguments>
                                <image>
                                    <builder>paketobuildpacks/builder:tiny</builder>
                                    <env>
                                        <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                                    </env>
                                </image>
                            </configuration>
                            <executions>
                                <execution>
                                    <id>process-aot</id>
                                    <goals>
                                        <goal>process-aot</goal>
                                    </goals>
                                </execution>
                            </executions>
                        </plugin>
                        <plugin>
                            <groupId>org.graalvm.buildtools</groupId>
                            <artifactId>native-maven-plugin</artifactId>
                            <configuration>
                                <classesDirectory>${project.build.outputDirectory}</classesDirectory>
                                <metadataRepository>
                                    <enabled>true</enabled>
                                </metadataRepository>
                                <requiredVersion>22.3</requiredVersion>
                                <buildArgs>
                                    --no-fallback
                                    --initialize-at-build-time=ch.qos.logback
                                    --initialize-at-build-time=org.slf4j
                                    --initialize-at-run-time=io.netty.channel.epoll.Epoll
                                    --initialize-at-run-time=org.slf4j.MDC
                                    --report-unsupported-elements-at-runtime
                                    --allow-incomplete-classpath
                                    --enable-url-protocols=http
                                    -H:+ReportExceptionStackTraces
                                </buildArgs>
                            </configuration>
                            <executions>
                                <execution>
                                    <id>add-reachability-metadata</id>
                                    <goals>
                                        <goal>add-reachability-metadata</goal>
                                    </goals>
                                </execution>
                            </executions>
                        </plugin>
                    </plugins>
                </pluginManagement>
            </build>
        </profile>
    </profiles>
</project>

如果遇到执行本地化失败的问题,请自行加上<buildArgs>部分的配置。不同的第三方包本地化失败的错误不尽相同,通过设置如下不同的初始化包或者类

  • --initialize-at-build-time
  • --initialize-at-run-time

搭建工程

  • https://github.com/Nepxion/DiscoveryTool/tree/console-springboot-3.x.x,访问并获取代码
  • automation-springboot-3.x.x基于Discovery高版本分支制作的,可以换成Discovery 6.x.x分支,过程如下
    • 下载Discovery 6.x.x最新源码
    • 根目录pom.xmlJava 8换成Java 17
    • GraalVM编译
  • automation-springboot-3.x.x根目录pom.xmldiscovery.version换成Discovery 6.x.x分支的版本号
  • automation-springboot-3.x.x根目录执行mvn clean install -DskipTests

执行Hint命令

注意:console-springboot-3.x.x模块已经创建好native-image的反射文件,该步骤不需要运行,除非第三方组件(例如:SpringBoot)版本更新。本文只介绍其用法

console-springboot-3.x.x模块为例,进入console-springboot-3.x.x目录

本地化之前需要把反射、JNI等类通过-agentlib命令生成这些类的Json形式的信息,创建到src\main\resources\META-INF\native-image\目录下

① 在console-springboot-3.x.x目录下,运行如下命令

mvn -Pnative clean spring-boot:run

或者直接运行根目录下install-hint.bat,注意batGraalVM的路径

② 应用启动后,等待一段时间(5秒或者10秒,或者更长),执行CTRL + C快捷键结束应用进程后,自动创建Hint相关文件

Hint命令执行过程中,需要注意:

  • Hint相关文件需要在Spring Boot 3.0应用的运行期创建相关文件,所以需要手工通过CTRL + C方式结束应用进程后才能创建那些文件,GraalVM官方插件有提供config-write-period-secsconfig-write-initial-delay-secs的超时结束线程参数,请自行研究
  • 如果应用中包含的包,是Java 8编译出来的,里面还有一些需要通过Json序列化和反序列化的实体类,需要对该包对应的源码用Java 17再编译一次,然后再执行Hint命令

执行Native命令

console-springboot-3.x.x模块为例,进入console-springboot-3.x.x目录

① 在console-springboot-3.x.x目录下,运行如下命令

mvn -Pnative native:compile -DskipTests

或者直接运行根目录下install-native.bat,注意batGraalVM的路径

② 等待1 ~ 2分钟(取决于计算机的配置优劣),在target目录下,会创建discovery-console.exe,可以直接运行,或者也可以通过startup.native.bat来运行

踩坑记录

① 资源文件的路径长度如果超过150个字符,该资源文件无法被本地化

② 包含Lambda语法的类代码,默认不会被本地化

③ 发现两个Issue,已经报给官方,目前无法解决

  • https://github.com/oracle/graal/issues/5678
  • https://github.com/spring-projects/spring-boot/issues/33637

参考资料

Spring Boot官方文档 https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.developing-your-first-application.buildpacks.maven

GraalVM官方文档 https://www.graalvm.org/22.3/reference-manual/native-image/metadata/AutomaticMetadataCollection/#tracing-agent

GraalVM官方示例 https://github.com/graalvm/native-build-tools/blob/master/samples/java-application-with-reflection/pom.xml




2017-2050 ©Nepxion Studio Apache License

           

Total visits

讲义篇

集成篇

概念篇

实践篇

功能篇

配置篇

扩展篇

测试篇

升级篇

贡献篇

Clone this wiki locally