GraalVM技術通過為Java應用進行靜態編譯,協助應用消除了冷啟動和運行時記憶體佔用高的問題。針對GraalVM應用,ARMS提供了靜態插裝方案,將應用運行時使用Java探針對位元組碼的改寫邏輯調整到靜態編譯中,實現靜態增強,提供開箱即用的可觀測能力。
GraalVM作為一項前沿技術,如果之前未在生產情境使用過,建議您在測試環境充分驗證後再考慮生產使用。此外,您在使用該方案接入ARMS過程中有任何問題,歡迎通過DingTalk答疑群(群號:80805000690)與我們聯絡。
使用限制
應用本身已完成GraalVM靜態編譯適配,如果是Spring Boot應用,可以參考相關文檔進行應用適配改造。
該方案需要調整GraalVM JDK實現,因此使用時需確保所使用的GraalVM JDK均為ARMS提供。
如果要使用GraalVM靜態編譯,其對環境有一些要求,具體要求請參見GraalVM官方文檔。
目前針對GraalVM情境,ARMS僅支援核心的Traces和Metrics功能,暫不支援Arthas、持續剖析和記憶體快照等功能,另外由於GraalVM情境下,應用記憶體形態有變化,因此JVM監控中的元空間詳情、非堆記憶體和直接緩衝區無資料是正常的。
接入操作
步驟一:安裝依賴
GraalVM情境下,首先需要在環境中安裝以下依賴:
根據自身應用所在地區,下載對應的GraalVM版本的ARMS探針。
當前僅支援以下地區,如有更多需求,請通過DingTalk答疑群(群號:80805000690)與我們聯絡。
地區
公網地址
VPC地址
華東1(杭州)
wget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipwget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip華東2(上海)
wget "http://arms-apm-cn-shanghai.oss-cn-shanghai.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipwget "http://arms-apm-cn-shanghai.oss-cn-shanghai-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip華北2(北京)
wget "http://arms-apm-cn-beijing.oss-cn-beijing.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipwget "http://arms-apm-cn-beijing.oss-cn-beijing-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip華北3(張家口)
wget "http://arms-apm-cn-zhangjiakou.oss-cn-zhangjiakou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipwget "http://arms-apm-cn-zhangjiakou.oss-cn-zhangjiakou-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip華南1(深圳)
wget "http://arms-apm-cn-shenzhen.oss-cn-shenzhen.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipwget "http://arms-apm-cn-shenzhen.oss-cn-shenzhen-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip解壓檔案後,進入ArmsAgentNative目錄,執行以下命令在本地環境中安裝探針。
sh install.sh下載支援可觀測能力的GraalVM JDK版本:graalvm-java17-23.0.4-ali-1.2b.tar.gz。
解壓後在對應目錄中執行以下命令:
graalvm-java17-23.0.4-ali-1.2b/bin/native-image --version返回結果如下表示安裝成功:

下載Maven(如果環境已有Maven,無需再次安裝):apache-maven-3.8.4-bin.tar.gz。
解壓後,將環境變數JAVA_HOME和MAVEN_HOME設定對應解壓檔案後的路徑。
例如:
請將
/xxx/換成實際路徑。export MAVEN_HOME=/xxx/apache-maven-3.8.4 export PATH=$PATH:$MAVEN_HOME/bin export JAVA_HOME=/xxx/graalvm-java17-23.0.4-ali-1.2b export PATH=$PATH:$JAVA_HOME/bin
步驟二:引入依賴
為應用添加如下依賴:
請將代碼中的路徑/xxx/dynamic-configs指嚮應用原始的動態設定檔地址。
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>arms-javaagent-native</artifactId>
<version>4.1.11</version>
<type>pom</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<fallback>false</fallback>
<buildArgs>
<arg>-H:ConfigurationFileDirectories=native-configs,/xxx/dynamic-configs</arg>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>步驟三:添加access-filter-file.json檔案
在應用目錄下,添加一個名為access-filter-file.json的檔案,其中內容為:
{ "rules": [
{"excludeClasses": "sun.launcher.LauncherHelper"}
]
}添加access-filter-file.json檔案用於確保GraalVM收集動態特性的探針不要收集sun.launcher.LauncherHelper中的反射。sun.launcher.LauncherHelper是JVM啟動的類,其中用到的反射對於靜態編譯後的Native Image是不需要的,否則會在編譯時間產生錯誤。
步驟四:預執行
為了讓ARMS探針對應用的動態增強代碼被靜態編譯到最終的Native Image檔案中,因此需要預先掛載ARMS探針對應用進行預執行,預執行需要確保應用核心代碼分支都被執行,當前已提供一個相關指令碼供您完成該過程。注意將應用的所有RESTful介面都按提示聲明在指令碼中,以便執行過程中的相關介面被正常調用觸發業務執行。
參考以下指令碼,按照注釋完成自訂內容補充。
######## 請根據實際修改一下參數 # ARMS接入參數, 可調用DescribeTraceLicenseKey介面擷取到對應的LicenseKey。AppName代表接入到ARMS的哪一個應用中,您可以根據需要自訂您的應用程式名稱,在分布式架構中,同一個應用內可以包含多個對等的執行個體。 export ARMS_LICENSEKEY= export ARMS_APPNAME= # 應用介面列表,例如PS=(interface1 interface2 interface3 interface4) export PS= # 應用連接埠,例如PORT="8080" export PORT= # Native image檔案路徑,靜態編譯後會在應用target目錄下產生一個native image檔案,例如NATIVE_IMAGE_FILE="target/graalvm-demo" export NATIVE_IMAGE_FILE= # 運行ARMS Native Agent的命令,例如JAVA_CMD="-javaagent:./arms-native/aliyun-java-agent-native.jar -jar target/graalvm-demo-1.0.0.jar" export JAVA_CMD= ########掛載ARMS Java探針,進入預執行,搜集靜態編譯的配置項。
sh ArmsAgentNative/run.sh --collect --jvm --Carms
步驟五:靜態編譯
完成依賴添加後,按照如下步驟對應用進行靜態編譯:
開始靜態編譯。
mvn -Pnative package運行靜態編譯後的專案。
sh ArmsAgentNative/run.sh --native --Carms
其他動作
構建Docker鏡像
如果要針對完成GraalVM靜態編譯後的應用構建Docker鏡像,由於其中已經包含了JDK等運行時必要的資訊,直接將最終的Native Image檔案作為一個可執行檔放到鏡像中,按照正常構建Docker鏡像流程進行鏡像構建即可。
樣本Dockerfile:
-Darms.licenseKey和-Darms.appName參數需調整為實際值。
FROM centos:latest
WORKDIR /app
COPY ./target/graalvm-demo /app
CMD ["/app/graalvm-demo","-Darms.licenseKey=xxx","-Darms.appName=xxx"]壓縮Native Image
在比較Native Image與原Java程式所佔的空間大小時,我們會將JDK的大小也加在Java程式側一起計算。因為Java程式必須要JDK支援,而Native Image是自舉的,它已經包含了所有的依賴。
但是因為Native Image中為彙編代碼,相比Java應用的位元組碼資訊密度更低,表達相同的語義所需的代碼量更大。因此隨著應用規模的增大,Native Image的大小會逐漸超越Java程式 + JDK的大小,導致部署、傳輸的壓力增大。此時我們可以藉助壓縮公用程式UPX來降低Native Image的大小。UPX可以將二進位可執行檔仍然壓縮為二進位可執行檔,壓縮後的檔案無需解壓即可直接運行,並且基本不會影響運行時的效能。
下圖展示了壓縮Native Image的效果:

將靜態編譯後的graalvm-demo檔案壓縮為graalvm-demo-compressed檔案,壓縮後的大小僅有之前的28.4%。
與Fat Jar包的比較:

原先包含了Spring Boot、RocketMQ等所有依賴的Fat Jar包大小為216MB,而壓縮後的Native Image僅有47MB。
UPX使用方法:
下載並解壓UPX工具。
假設UPX被解壓到
$UPX_HOME目錄,執行以下命令完成壓縮。$UPX_HOME/upx -9 -o path/to/output-file path/to/original-file-9:壓縮程度為1~9,值越大壓縮率越高,壓縮所需時間越長。-o path/to/output-file:壓縮輸出檔案路徑,path/to/output-file需要換成實際的檔案路徑。path/to/original-file:被壓縮的原始檔案路徑,path/to/original-file需要換成實際的檔案路徑。