輕量靈動:革新輕量級服務開發

導讀

Java 雖然在市場份額佔比巨大,但是在萬物雲原生下,因它啓動時長,資源消耗較大,不易水平擴展等方面都成爲了明顯的短板,導致市場份額也逐漸減少。而 GraalVM 彌補了這些缺陷,本文將從實戰方向帶你打開,原生鏡像之路。

01 概念篇

在今年的敏捷團隊建設中,我通過 Suite 執行器實現了一鍵自動化單元測試。Juint 除了 Suite 執行器還有哪些執行器呢?由此我的 Runner 探索之旅開始了!

1.1  從 JDK8->JDK17 你需要知道的

從 JDK 8 升級到 JDK 17 可以讓你的應用程序受益於新的功能、性能改進和安全增強。下面是一些 JDK 8 升級到 JDK 17 的最佳實戰:

1.1.1 確定升級的必要性:

首先,你需要評估你的應用程序是否需要升級到 JDK 17。查看 JDK 17 的新特性、改進和修復的 bug,以確定它們對你的應用程序是否有實際的好處。

1.1.2 瞭解 JDK 8 到 JDK 17 的變化:

詳細瞭解 JDK 8 和 JDK 17 之間的差異是非常重要的。熟悉 JDK 17 中引入的新特性、移除的特性以及可能影響現有代碼的變化。

1.1.3 解決向後不兼容的變化 更新依賴項和框架:

在升級過程中,可能會遇到一些向後不兼容和框架不兼容的變化。例如,一些 API 的使用方式可能發生了變化,或者一些方法已被廢棄。在升級之前,你需要對這些變化進行仔細的檢查,並相應地修改你的代碼。

1.1.4 進行兼容性測試:

在升級之前,進行兼容性測試是非常重要的。確保你的應用程序在 JDK 17 下能夠正常運行,並且沒有出現任何性能下降或功能問題。可以使用自動化測試工具來簡化測試過程。

1.1.5 逐步升級:

對於大型應用程序或關鍵系統,建議逐步進行升級。可以先將應用程序遷移到較新的 JDK 版本,如 JDK 11 或 JDK 14,然後再逐步升級到 JDK 17。這樣可以降低升級過程中的風險,並使你能夠逐步解決遇到的問題。

1.1.6 監控和優化性能:

升級到 JDK 17 後,你可能會注意到一些性能改進。然而,某些代碼可能會受到影響並表現出不同的行爲。使用性能監控工具來檢測潛在的性能問題,並進行必要的調整和優化。

1.1.7  更新部署和運維流程:

升級 JDK 版本後,你可能還需要更新你的部署和運維流程。例如,JDK 17 中引入了一些新的命令行工具和管理選項。

1.2  爲什麼要使用 jdk17?

1.2.1 長期支持(LTS):

JDK 版本中的一些版本被標記爲長期支持版本,這意味着它們將獲得更長時間的支持和維護。JDK 17 是 OpenJDK 的一個 LTS 版本。

1.2.2 生態系統支持:

一些開源項目、框架和工具可能會更早地支持較新的 JDK 版本,以利用新的特性和改進。選擇較新的 JDK 版本可以使你能夠使用最新的工具和庫,並獲得更好的生態系統支持。

1.2.3 新功能和改進:

每個 JDK 版本都會引入新的功能、增強和改進。

1.3  強強聯合 GraalVM

GraalVM 是一種開源的【通用】虛擬機(通用: 它具有支持多種編程語言的能力 直接在 graalvm 運行 不需要額外的運行時環境),具有許多特性和優勢,使得它在特定的場景中成爲一個有吸引力的選擇。以下是一些使用 GraalVM 的原因:

1.3.1 高性能:

GraalVM 具有優化的即時編譯器,能夠將 Java 程序編譯成高效的機器碼。在許多情況下比傳統的 Java 虛擬機更快。

1.3.2 AOT 編譯:

GraalVM 可以將 Java 程序靜態編譯成本地機器碼,這被稱爲 Ahead-of-Time(AOT)編譯。AOT 編譯可以提供更快的啓動時間和更低的內存消耗,適用於一些對性能要求較高的場景。

1.3.3 生態系統支持:

GraalVM 在開發者社區中有廣泛的支持和活躍的生態系統。許多開源項目和框架已經對 GraalVM 進行了優化和集成,使得使用 GraalVM 更加方便和無縫。

1.3.4 嵌入式支持:

GraalVM 提供了嵌入式 API,允許你將 GraalVM 作爲庫集成到你的應用程序中。這意味着你可以將 GraalVM 作爲運行時引擎嵌入到你的應用程序中,從而實現更高的靈活性和自定義性。

1.3.5 雲原生支持:

GraalVM 具有與雲原生應用程序開發和部署相關的特性。它可以與 Docker 和 Kubernetes 配合使用,支持快速啓動和低內存消耗,適用於雲環境中的微服務架構。

02  實戰篇

理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。     

2.1  第一步建議先升級依賴項

    

如果你的項目基於 java 8,在升級前最好先升級依賴項,從 java 8 升級到 java 17 是一個很大的跨越,依賴項不升級則出問題的概率會比較高,maven 可以用mvn versions:display-dependency-updates命令檢查依賴項更新,輸出會類似這樣:

圖 1. 檢查依賴項更新輸出示意

然後可以把依賴項升級到輸出的對應版本,大部分包升級不會出問題,如果有問題,建議去出問題的依賴官方倉庫尋找解決方案。這個命令是直接查詢 maven 遠程倉庫,如果依賴項多的話會運行比較長的時間

或者 jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar

javax.annotation.* 被移除 可以手動倒入

dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
</dependency>

常見的標記爲廢棄的參數 遷移前後的參數如下:

圖 2. 遷移前後的參數示意

2.2  環境安裝

2.2.1 Jdk 環境安裝 https://www.graalvm.org/downloads/

版本對比、一張官方的對比圖

圖 3. 官方的版本對比圖示意

升級時 springboot 和 springcloud 版本對應表:https://start.spring.io/actuator/info

2.2.2 maven 環境安裝 https://maven.apache.org/download.cgi

GraalVM 對 maven 沒有特定的版本要求。通常情況下,只要您使用的 Maven 版本足夠新並支持 Java 8 或更高版本,就可以與 GraalVM 一起使用。建議您使用 Maven 3.5.x 或更高版本以確保與 GraalVM 的兼容性。

啓動java器使用 GraalVM 默認編譯器 Graal 運行 JVM。安裝時檢查 Java 版本:

$JAVA_HOME/bin/java -version

2.3  二進制的生成

    

2.3.1 安裝本機映像

gu install native-image
該native-image工具安裝在$JAVA_HOME/bin目錄中

2.3.2 maven 構建

mvn clean package -Pnative -Dmaven.test.skip=true

2.4 出現的坑點

2.4.1 對於 mac 提前安裝 glibc-devel

2.4.2 對於 centos 提前安裝

yum install centos-release-scl

yum install devtoolset-8

source /opt/rh/devtoolset-8/enable

yum install zlib-devel

否則編譯出現 會編譯失敗 gcc 需要升級到 6.4 以上

報錯如下:

圖 4、5. 報錯示意

2.4.3 對於 java 應用來說 打出來的二進制可能出現亂碼 因此需要強制指定

圖 6. 強制指定示意

2.5  模塊化 初體驗

 git clone https://github.com/graalvm/graalvm-demos
 cd graalvm-demos/native-hello-module
 結構圖
 ├── hello
   └── Main.java
       > package hello;
       > 
       > public class Main {
       >     public static void main(String[] args) {
       >         System.out.println("Hello from Java Module: "
       >             + Main.class.getModule().getName());
       >     }
       > }

└── module-info.java
    > module HelloModule {
    >     exports hello;
    > }
 mvn package
 $JAVA_HOME/bin/java --module-path target/HelloModule-1.0-SNAPSHOT.jar --module HelloModule
 $JAVA_HOME/bin/native-image --module-path target/HelloModule-1.0-SNAPSHOT.jar --module HelloModule
 ./hellomodule

2.6  編譯器操作模式

Graal 作爲 HotSpot JIT 編譯器有兩種運行模式:

libgraal:Graal 編譯器提前編譯到本地共享庫中。在這種運行模式下,共享庫由 HotSpot VM 加載。編譯器使用與 HotSpot 堆分開的內存,並且從一開始就運行得很快,因爲它不需要預熱。這是默認和推薦的操作模式。

jargraal:Graal 編譯器經歷與 Java 應用程序的其餘部分相同的預熱階段。也就是說,在編譯其熱方法之前首先對其進行解釋。-XX:-UseJVMCINativeLibrary 使用命令行選項選擇此模式。這將延遲達到最佳性能的時間。

2.7  本機映像構建配置

maven常用配置
<buildArgs>
如果要將其他參數傳遞給本機圖像生成器,請<buildArgs> 在插件的配置中使用
<buildArgs>
    <arg>--argument</arg>
</buildArgs>
<skipNativeBuild>
要跳過本機圖像的生成,請在插件的配置中提供以下內容:
<skipNativeBuild>true</skipNativeBuild>
<skipNativeTests>
要跳過本機圖像編譯測試的生成和執行,請在插件的配置中提供以下內容:
<skipNativeTests>true</skipNativeTests>
<debug>
如果要啓用調試信息的生成,請在插件配置中提供以下內容:
<debug>true</debug>
<useArgFile>
如果要使用參數文件構建原生圖像,請在插件配置中提供以下內容:
<useArgFile>true</useArgFile>

2.8  日誌記錄添加到本機可執行文件

1、默認情況下,由 Native Image 生成的本機可執行文件支持通過 java.util.logging.*API 進行日誌記錄。

2、本機可執行文件中的默認日誌記錄配置基於 logging.properties 在 JDK 中找到的文件。該文件配置了一個 java.util.logging.ConsoleHandler 只顯示該 INFO 級別及以上級別的消息的文件, 如果您需要額外的日誌記錄處理程序,則必須註冊相應的類以進行反射。例如,如果您使用 java.util.logging.FileHandlerthen 提供以下反射配置:

{
    "name" : "java.util.logging.FileHandler",
    "methods" : [
      { "name" : "<init>", "parameterTypes" : [] },
    ]
  }

3、將以下 Java 代碼保存到名爲 LoggerRunTimeInit.java 的文件中,然後使用以下命令對其進行編譯javac

import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.LogManager;
 import java.util.logging.Logger;
 public class LoggerTest {
     public static void main(String[] args) throws IOException {
         LogManager.getLogManager().readConfiguration(LoggerRunTimeInit.class.getResourceAsStream("/logging.properties"));
         Logger logger = Logger.getLogger(LoggerRunTimeInit.class.getName());
         logger.log(Level.WARNING");
     }
 }

4、下載 logging.properties 資源文件 (https://www.graalvm.org/docs/reference-manual/native-image/assets/logging.properties) 並將其保存在與 LoggerRunTimeInit.java 相同的目錄中。

5、構建並運行本機可執行文件:

 native-image LoggerTest -H:IncludeResources="logging.properties"
  ./LoggerTest

6、它應該產生類似於以下內容的輸出:

WARNING

2.9  使用 jdk17 和 graalvm 你可以體驗到

  1. 啓動時間:GraalVM 提供了 Just-In-Time (JIT) 編譯和 Ahead-Of-Time (AOT) 編譯的能力。AOT 編譯可以將 Java 應用程序編譯成本地機器碼,從而加快應用程序的啓動時間。相比之下,傳統的 JIT 編譯需要一些啓動時間來進行動態編譯。因此,使用 GraalVM 的 AOT 編譯可能會顯著減少啓動時間,提高應用程序的響應性能。

  2. 內存佔用:GraalVM 的 AOT 編譯可以減少應用程序的內存佔用,因爲本地機器碼通常比解釋執行的字節碼更加緊湊。這可以提高應用程序的可擴展性和資源利用率。

  3. 即時編譯性能:GraalVM 的 JIT 編譯器在某些情況下可能會提供更好的性能。它可以對熱點代碼進行更優化的編譯,以提高執行速度。這可能在一些計算密集型任務或高併發場景中帶來性能提升。

  4. 應用本身大小:在真實環境下佔用對比,且二進制版本是已經整合 5 個項目的完整項目,而 jar 只是其中 1/5。‍

圖 7. 應用本身大小對比示意

2.10  demo 開箱即體驗

經過真實項目驗證的框架 demo 已上傳至 github,地址:kafka-stream (https://github.com/17734671027/kafka-stream)基於 JDK17+springboot3.0.6+kafkaStream 構成,支持 native-image 打包,讓您下的開心,用的舒心 ,歡迎大家體驗。

03   總結

理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。     

在雲原生下,Java 升級到最新版本並使用 GraalVM 可以提高 Java 應用的性能、體驗新特性、提高資源利用率和適應萬物雲原生的能力。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/lpnXHrZ_Xe9GKP1RmbvQ2A