全部產品
Search
文件中心

Application Real-Time Monitoring Service:將GraalVM應用接入ARMS

更新時間:May 15, 2025

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情境下,首先需要在環境中安裝以下依賴:

  1. 根據自身應用所在地區,下載對應的GraalVM版本的ARMS探針。

    當前僅支援以下地區,如有更多需求,請通過DingTalk答疑群(群號:80805000690)與我們聯絡。

    地區

    公網地址

    VPC地址

    華東1(杭州)

    wget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip
    wget "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.zip
    wget "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.zip
    wget "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.zip
    wget "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.zip
    wget "http://arms-apm-cn-shenzhen.oss-cn-shenzhen-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip

    解壓檔案後,進入ArmsAgentNative目錄,執行以下命令在本地環境中安裝探針。

    sh install.sh
  2. 下載支援可觀測能力的GraalVM JDK版本:graalvm-java17-23.0.4-ali-1.2b.tar.gz

    解壓後在對應目錄中執行以下命令:

    graalvm-java17-23.0.4-ali-1.2b/bin/native-image --version

    返回結果如下表示安裝成功:

    image

  3. 下載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介面都按提示聲明在指令碼中,以便執行過程中的相關介面被正常調用觸發業務執行。

  1. 參考以下指令碼,按照注釋完成自訂內容補充。

    ######## 請根據實際修改一下參數
    # 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=
    ########
  2. 掛載ARMS Java探針,進入預執行,搜集靜態編譯的配置項。

    sh ArmsAgentNative/run.sh --collect --jvm --Carms

步驟五:靜態編譯

完成依賴添加後,按照如下步驟對應用進行靜態編譯:

  1. 開始靜態編譯。

    mvn -Pnative package
  2. 運行靜態編譯後的專案。

    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的效果:

image

將靜態編譯後的graalvm-demo檔案壓縮為graalvm-demo-compressed檔案,壓縮後的大小僅有之前的28.4%。

與Fat Jar包的比較:

image

原先包含了Spring Boot、RocketMQ等所有依賴的Fat Jar包大小為216MB,而壓縮後的Native Image僅有47MB。

UPX使用方法:

  1. 下載並解壓UPX工具

  2. 假設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需要換成實際的檔案路徑。