支援 Graal VM

dubbo 3.0 支援 native-image 文件

功能說明

本文將介紹 dubbo 3.0 專案連接 GraalVM 並將 native-image 編譯成二進位檔的過程。

更多關於 GraalVM 的資訊可以閱讀https://graalvm.dev.org.tw/docs/getting-started/container-images/此文件。

使用場景

使用方法

在編譯我們的 dubbo 專案之前,我们需要確保我們基於 graalVM 環境。

安裝 GraalVM

前往https://graalvm.dev.org.tw/官方網站,根據您的系統選擇最新版本進行安裝

img

安裝完成後,修改路徑配置 JAVA_HOME,生效後檢查本地 jdk,可以看到如下

img 這裡我們使用基於 jdk1.8 版本的 GraalVM。

  • 要安裝 native-image,只需執行 gu install native-image。
  1. 拉取 dubbo 程式碼並切換到 apache:3.0 分支。
  2. 手動執行生成的 SPI 程式碼。

由於目前 native-image 的編譯不支援程式碼動態產生和編譯,因此需要手動產生與程式碼動態產生相關的部分。這裡有一個工具函式

img 執行 CodeGenerator 在 dubbo-native 模組下產生 SPI 程式碼。

在根目錄執行 install

MacdeMacBook-pro-3:incubator-dubbo mac$ pwd

/Users/mac/Documents/Mi/project/incubator-dubbo

MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true

編譯 demo 專案

這裡我們提供了一個可以直接編譯的範例專案,dubbo-demo/dubbo-demo-native。安裝完上述步驟後,先到 dubbo-demo-native 的 provider 執行 native-image 編譯

 mvn clean package -P native -Dmaven.test.skip=true

這裡,由於我們在 maven 中引入了 native-image 外掛,可以直接執行外掛 -P native。

img 編譯成功後,您可以在 target 目錄下看到生成的二進位檔案,在本機啟動一個 ZooKeeper,然後直接執行該二進位檔案。可以看到如下所示的啟動成功畫面。

img consumer 端也執行編譯,在 consumer 的 target 目錄下也會生成一個二進位檔案:demo-native-consumer。執行此二進位檔案,您可以看到如下所示的呼叫結果。

img

具體步驟

實際上,我們已經在此 demo 下完成了一些工作,以確保專案可以編譯和執行。主要步驟如下:

  • 引入 dubbo-native 依賴
<dependency>

    <groupId>org.apache.dubbo</groupId>

    <artifactId>dubbo-native</artifactId>

    <version>${project.version}</version>

</dependency>

此模組下是我們生成的 SPI 程式碼。

  • 引入 native-image 插件
<plugin>

    <groupId>org.graalvm.nativeimage</groupId>

    <artifactId>native-image-maven-plugin</artifactId>

    <version>21.0.0.2</version>

    <executions>

        <execution>

            <goals>

                <goal>native-image</goal>

            </goals>

            <phase>package</phase>

        </execution>

    </executions>

    <configuration>

        <skip>false</skip>

        <imageName>demo-native-provider</imageName>

        <mainClass>org.apache.dubbo.demo.graalvm.provider.Application</mainClass>

        <buildArgs>

            --no-fallback

            --initialize-at-build-time=org.slf4j.MDC

            --initialize-at-build-time=org.slf4j.LoggerFactory

            --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder

            --initialize-at-build-time=org.apache.log4j.helpers.Loader

            --initialize-at-build-time=org.apache.log4j.Logger

            --initialize-at-build-time=org.apache.log4j.helpers.LogLog

            --initialize-at-build-time=org.apache.log4j.LogManager

            --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent

            --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory

            --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter

            --initialize-at-build-time=org.eclipse.collections.api.factory.Sets

            --initialize-at-run-time=io.netty.channel.epoll.Epoll

            --initialize-at-run-time=io.netty.channel.epoll.Native

            --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop

            --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray

            --initialize-at-run-time=io.netty.channel.DefaultFileRegion

            --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray

            --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop

            --initialize-at-run-time=io.netty.channel.kqueue.Native

            --initialize-at-run-time=io.netty.channel.unix.Errors

            --initialize-at-run-time=io.netty.channel.unix.IovArray

            --initialize-at-run-time=io.netty.channel.unix.Limits

            --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger

            --initialize-at-run-time=io.netty.channel.unix.Socket

            --initialize-at-run-time=io.netty.channel.ChannelHandlerMask



            --report-unsupported-elements-at-runtime

            --allow-incomplete-classpath

            --enable-url-protocols=http

            -H:+ReportExceptionStackTraces

        </buildArgs>

    </configuration>

</plugin>

它定義了生成映像的名稱以及構建映像的一些參數。

  • 掛載 native-image-agent

由於我們需要先指定一些反射、JNI 和其他類別,因此需要使用 agent 以正常方式執行它,以便為這些類別生成 json 格式的資訊。

在啟動參數中新增

-agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5

以正常方式啟動,在專案的 resources 目錄下建立一個 META-INF.native-image 資料夾,並將在本機目錄中生成的檔案貼上到該資料夾中。

img (可能會有缺少未生成的類別資訊,需要根據編譯或執行時的錯誤訊息手動新增。)

**完成上述步驟後,即可編譯專案。**


最後修改日期:2023 年 2 月 23 日:SEO/圖片 alt 更新 (35090e3f9b4)