GraalVM是一種高性能的多語言虛擬機,用於運行以JavaScript等基於LLVM的各種語言編寫的應用程序。對於Java應用也可作為通常JVM的替代,它更具有性能優勢。GraalVM帶來的一個有趣功能是它能夠在創建JVM應用程序的提前編譯(create ahead-of-time:AOT)本機鏡像,從而保證了更快的啟動時間和更低的內存占用。在本文中,我們將重點介紹如何創建Spring應用的本機二進制文件。
GraalVM Native Image 101
Java應用程序使用編譯為字節碼javac。在應用程序運行時,JVM將類文件加載到內存中,並分析程序的性能以獲取熱點。因此名稱為“ HotSpot JVM ”。在剛剛在時間(JIT)編譯器編譯這些重復執行為本機代碼應用程序的部分。 但是,JIT編譯需要處理器時間和內存,這會影響應用程序的啟動時間。
GraalVM原生本機鏡像能提前將 JVM應用程序編譯為當前機器的機器代碼。它靜態分析應用程序的字節碼,找到所有可以訪問的類和方法,並將它們編譯為本地可執行文件。輸出是特定於平台的可執行二進制文件。
例如,讓我們從以下“ Hello World”程序構建原生鏡像。
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
首先,我們需要使用 javac:
$ javac HelloWorld.java
然后用native-image將這個類文件構建成可執行二進制文件。
$ native-image HelloWorld
要啟動應用程序,只需:
$ ./helloworld
Hello World
本機鏡像Java限制
GraalVM本機鏡像靜態分析是需要假設在封閉世界的前提下。它需要在鏡像生成期間提前知道所有可能訪問的字節碼。因此,並非所有Java功能都受支持:例如,不支持動態類的加載/卸載。反射需要配置。CGLIB代理不適用,但是卻支持JDK代理,還需要配置。此外,您還需要告訴本機鏡像有關所有資源訪問的信息。
配置以JSON文檔的形式提供。例如,要配置反射,您可以創建以下文件,並使用-H:ReflectionConfigurationFiles命令行標志來指定命令的文件位置native-image。
[
{ "name":"java.lang.Object" },
{ "name":"org.apache.naming.factory.ResourceFactory", "methods" : [{"name": "<init>","parameterTypes":[]}] },
...
]
配置動態代理、JNI和資源訪問時都需要創建類似的文件來。但是,手工完成所有這些工作需要很多工作,尤其是在我們處理大型應用程序時。幸運的是,有一個Java代理可以生成配置。它觀察在JVM中運行的應用程序的行為,並生成生成本機映像所需的配置文件。
要獲得完整的配置文件集,您需要在應用程序中使用所有代碼路徑。具有100%覆蓋率的測試套件可以解決問題,但實際上,測試套件永遠不會測試所有路徑。因此,也可能需要手動修改這些配置文件。
Spring和GraalVM本機映像
從Spring Framework 5.1 開始,提供了對GraalVM本機映像的初始支持。 5.2開發周期的重點是改進集成和全面支持,而不需要額外的配置或變通辦法,這是即將到來的Spring Framework 5.3發行版的主題之一。
在spring-graal-nativeGithub上庫展示了如何從Spring啟動應用程序構建本地鏡像的例子。該項目實施了GraalFeature,在配置反射,代理等方面承擔了繁重的工作。
看看Spring Boot帶有Tomcat的Spring MVC示例:請記住,在撰寫本文時,該示例期望您正在使用GraalVM 19.2.1,並且已native-image安裝插件。在構建示例之前,我們需要編譯Spring Graal Feature。github存儲庫的根目錄具有一個bash腳本來執行此操作。
$ ./build-feature.sh
完成后,讓我們轉到Spring MVC example文件夾並執行compile.sh。它使用Maven構建Spring應用程序,然后生成GraalVM本機映像。該native-image命令隨Spring Graal功能部件的位置以及各種配置文件一起提供。請注意,本機映像生成比常規Maven構建花費的時間要長得多。另外,該進程喜歡使用大量RAM。完成后,導航到該target文件夾並啟動應用程序
$ ./springmvc-tomcat
. ____ _ __ _ _
/\ / ' __ _ () __ __ _ \ \ \
( ( )__ | '_ | '| | ' / ` | \ \ \
\/ )| |)| | | | | || (| | ) ) ) )
' || .__|| ||| |__, | / / / /
=|_|======|/=////
:: Spring Boot ::
...
INFO: Started TomcatApplication in 0.054 seconds (JVM running for 0.057)
注意0.054秒的快速啟動時間。為了進行比較,在JVM中運行應用程序時,報告的啟動時間為1.455秒。
總結
GraalVM本機映像使我們能夠構建提前編譯的JVM應用程序,這些應用程序啟動速度非常快,並且使用的內存更少。這對於短暫的過程絕對是有用的,尤其是在無服務器的情況下(按毫秒計費)。
由於類路徑掃描和自動配置,Spring Boot應用程序在啟動期間非常占用CPU。當在共享主機上同時啟動多個Spring Boot應用程序時,它們開始爭奪CPU,啟動時間增加。編排工具甚至可能終止進程,因為它們啟動得不夠快。快速啟動的提前編譯的Spring Boot應用程序可能是該問題的答案。
容器化的Spring Boot應用程序也會有所收獲。由於本機二進制文件具有所需的一切,因此不再需要將JRE烘焙到容器中。我們可以構建較小的Docker映像。
一些以微服務為重點的框架已經利用了本機圖像功能(例如Quarkus,Micronaut,Helidon)。盡管Spring Boot尚未完全支持本機映像生成,但我認為它將是該框架的重要補充。
原文地址:
https://blog.indrek.io/articles/running-spring-boot-apps-as-graalvm-native-images/
