偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

基于靜態(tài)編譯構(gòu)建微服務(wù)應(yīng)用

開(kāi)發(fā)
上述過(guò)程既給 Java 程序帶來(lái)了其他編程語(yǔ)言不具備的優(yōu)勢(shì),比如跨平臺(tái),易上手等。但同時(shí)也給 Java 程序帶來(lái)了一些性能問(wèn)題,比如啟動(dòng)速度慢和運(yùn)行時(shí)內(nèi)存占用高等。

Java 的局限性

傳統(tǒng)的一個(gè) Java 應(yīng)用從代碼編寫(xiě)到啟動(dòng)運(yùn)行大致可以分為如下步驟:

  1. 首先,編寫(xiě) .java 源代碼程序。
  2. 然后,借助 javac 工具將 .java 文件翻譯為 .class 的字節(jié)碼,字節(jié)碼是 Java 中非常重要的內(nèi)容之一,正是因?yàn)樗某霈F(xiàn),Java 才實(shí)現(xiàn)對(duì)底層環(huán)境的屏蔽,達(dá)到 Write once, run anywhere 的效果!
  3. 基于步驟 2 的 .class 文件會(huì)被打包成 jar 包或者 war 包進(jìn)行部署執(zhí)行,部署過(guò)程中通過(guò) Java 虛擬機(jī)加載應(yīng)用程序然后解釋字節(jié)碼運(yùn)行業(yè)務(wù)邏輯。

整個(gè)過(guò)程如下圖所示:圖片

圖 1:Java 程序運(yùn)行過(guò)程

上述過(guò)程既給 Java 程序帶來(lái)了其他編程語(yǔ)言不具備的優(yōu)勢(shì),比如跨平臺(tái),易上手等。但同時(shí)也給 Java 程序帶來(lái)了一些性能問(wèn)題,比如啟動(dòng)速度慢和運(yùn)行時(shí)內(nèi)存占用高等。

冷啟動(dòng)問(wèn)題

圖 1 中 Java 程序啟動(dòng)運(yùn)行詳細(xì)過(guò)程如下圖 2 所示:

圖片

圖 2:Java 程序的啟動(dòng)過(guò)程分析[1]

一個(gè) Java 應(yīng)用啟動(dòng)過(guò)程首先需要加載該應(yīng)用程序?qū)?yīng)的 JVM 虛擬機(jī)軟件程序到內(nèi)存中,如上圖紅色部分描述所示。然后 JVM 虛擬機(jī)再加載對(duì)應(yīng)的應(yīng)用程序到內(nèi)存中,該過(guò)程對(duì)應(yīng)上圖中的淺藍(lán)色類(lèi)加載(Class Load,CL)部分。在類(lèi)加載過(guò)程中,應(yīng)用程序就會(huì)開(kāi)始被解釋執(zhí)行,對(duì)應(yīng)上圖中淺綠色部分。解釋執(zhí)行過(guò)程 JVM 對(duì)垃圾對(duì)象進(jìn)行回收,對(duì)應(yīng)上圖中的黃色部分。隨著程序的運(yùn)行的深入,JVM 會(huì)采用及時(shí)編譯(Just In Time,JIT)技術(shù)對(duì)執(zhí)行頻率較高的代碼進(jìn)行編譯優(yōu)化,以便提升應(yīng)用程序運(yùn)行速度。JIT 過(guò)程對(duì)應(yīng)上圖中的白色部分。經(jīng)過(guò) JIT 編譯優(yōu)化后的代碼對(duì)應(yīng)圖中深綠色部分。

經(jīng)過(guò)上述分析,不難看出,一個(gè) Java 程序從啟動(dòng)到達(dá)到被JIT動(dòng)態(tài)編譯優(yōu)化會(huì)經(jīng)過(guò) VM init,App init 和 App active 幾個(gè)階段,相比于其他一些編譯型語(yǔ)言,其冷啟動(dòng)問(wèn)題比較嚴(yán)重。

運(yùn)行時(shí)內(nèi)存占用高問(wèn)題

除了冷啟動(dòng)問(wèn)題,從上述分析中不難看出,一個(gè) Java 程序運(yùn)行過(guò)程中,什么都不做首先就需要加載一個(gè) JVM 虛擬機(jī),該操作一般占用一定內(nèi)存。另外,由于 Java 程序是先解釋執(zhí)行字節(jié)碼,然后再做 JIT 編譯優(yōu)化。

由于相比于一些編譯型語(yǔ)言其將編譯優(yōu)化的動(dòng)作后置到運(yùn)行時(shí),因此非常容易出現(xiàn)實(shí)際加載的代碼比實(shí)際需要運(yùn)行的代碼多很多的情況,造成了一些無(wú)效內(nèi)存占用情況。綜上所述就是為什么很多人常詬病 Java 程序運(yùn)行內(nèi)存占用高的幾點(diǎn)主要原因。

更輕量化的 Java 程序

靜態(tài)編譯技術(shù)

既然,先解釋執(zhí)行再動(dòng)態(tài)編譯的 Java 傳統(tǒng)程序運(yùn)行方式存在上述諸多問(wèn)題,那有沒(méi)有一些方式可以讓 Java 程序也跟其他程序語(yǔ)言,比如 C/C++ 一樣,先編譯后執(zhí)行解決上述問(wèn)題呢?

答案是肯定的,提前編譯(Ahead-of-Time Compilation,AOT Compilation)或者叫靜態(tài)編譯在 Java 領(lǐng)域很早就被提了出來(lái)。其核心思想就是將 Java 程序的編譯階段提前到程序啟動(dòng)前,然后在編譯階段進(jìn)行代碼編譯優(yōu)化,讓程序啟動(dòng)既巔峰,消除冷啟動(dòng),降低運(yùn)行時(shí)內(nèi)存開(kāi)銷(xiāo)。

Java 領(lǐng)域靜態(tài)編譯的實(shí)現(xiàn)技術(shù)有很多,其中最具代表性的還屬 Oracle 推出的 GraalVM 開(kāi)源高性能多語(yǔ)言運(yùn)行時(shí)平臺(tái)[2]。看到這里有的讀者可能會(huì)問(wèn):“高性能多語(yǔ)言運(yùn)行時(shí)平臺(tái)是什么?它跟靜態(tài)編譯本身有什么關(guān)系?”。

圖片

圖 3:GraalVM 多語(yǔ)言運(yùn)行時(shí)平臺(tái)

如上圖 3 所示,GraalVM 中通過(guò)提供 Truffle 解釋器實(shí)現(xiàn)框架,讓開(kāi)發(fā)人員可以使用 Truffle 提供的 API 快速實(shí)現(xiàn)特定語(yǔ)言的解釋器從而實(shí)現(xiàn)對(duì)上圖中各種編程語(yǔ)言所寫(xiě)的程序都能進(jìn)行編譯運(yùn)行的效果,從而成為一個(gè)多語(yǔ)言運(yùn)行時(shí)平臺(tái)。GraalVM 實(shí)現(xiàn)靜態(tài)編譯能力的編譯器就是 GraalVM JIT Compiler。靜態(tài)編譯框架和運(yùn)行時(shí)由 Substrate VM 子項(xiàng)目實(shí)現(xiàn),兼容 OpenJDK 運(yùn)行時(shí)實(shí)現(xiàn),提供了原生鏡像程序運(yùn)行時(shí)的異常處理、同步調(diào)度、線程管理、內(nèi)存管理等功能。

因此,GraalVM 不僅可以作為一個(gè)多語(yǔ)言運(yùn)行時(shí)平臺(tái),而且由于其中提供的 GraalVM JIT Compiler 靜態(tài)編譯器,其可用來(lái)對(duì) Java 程序進(jìn)行靜態(tài)編譯。

說(shuō)完靜態(tài)編譯和 GraalVM 之間的關(guān)系,有的讀者可能會(huì)好奇,基于 GraalVM 的靜態(tài)編譯與常規(guī)的 JVM 解釋執(zhí)行方式有哪些區(qū)別?基于靜態(tài)編譯的 Java 程序相比于目前應(yīng)用廣泛的 JVM 運(yùn)行時(shí)編譯 Java 程序整個(gè)從代碼編寫(xiě)到編譯執(zhí)行的區(qū)別如下圖 4 所示:

圖片

圖 4:靜態(tài)編譯與傳統(tǒng) JVM 運(yùn)行過(guò)程對(duì)比

相比于 JVM 運(yùn)行時(shí)方式,靜態(tài)編譯在運(yùn)行之前會(huì)先對(duì)程序解析編譯,然后生成一個(gè)跟運(yùn)行時(shí)環(huán)境強(qiáng)相關(guān)的 native image 可執(zhí)行文件,最后直接執(zhí)行該文件即可啟動(dòng)程序進(jìn)行執(zhí)行。

說(shuō)到這里可能有的讀者又好奇,上圖 4 中的靜態(tài)編譯過(guò)程到底會(huì)對(duì) Java 程序做哪些解析操作?靜態(tài)編譯后的可執(zhí)行程序垃圾回收問(wèn)題怎么解決?如下圖 5 所示,其描述了 GraalVM 靜態(tài)編譯技術(shù)實(shí)現(xiàn)中編譯過(guò)程的輸入與輸出內(nèi)容。

圖片

圖 5:靜態(tài)編譯輸入輸出

圖 5 中左側(cè)前三個(gè)輸入內(nèi)容 Applicaton,Libraries 和 JDK 是一個(gè) Java 程序編譯運(yùn)行必備的三部分,不必多說(shuō)。而 Substrate VM 就是 GraalVM 中實(shí)現(xiàn)靜態(tài)編譯的核心部分,在整個(gè)靜態(tài)編譯過(guò)程中扮演了重要作用。

其中在靜態(tài)分析過(guò)程中,如上圖 5 中間部分中所繪制,Substrate VM 通過(guò)上下文不敏感的指向分析(Points-to Analysis)來(lái)對(duì)應(yīng)用程序做靜態(tài)分析,其可以在不需要運(yùn)行程序的情況下,基于源程序分析給出所有可能的可達(dá)函數(shù)列表然后作為后續(xù)編譯階段的輸入對(duì)程序進(jìn)行靜態(tài)編譯。該過(guò)程由于靜態(tài)分析的局限性,無(wú)法覆蓋 Java 中的反射、動(dòng)態(tài)代理、JNI 調(diào)用等動(dòng)態(tài)特性。這也造成了很多的 Java 框架由于在實(shí)現(xiàn)過(guò)程中使用了大量的上述特性,因此,都難以直接基于 Substrate VM 完成對(duì)自身所有代碼的靜態(tài)分析,需要通過(guò)額外的外部配置[3]來(lái)解決靜態(tài)分析本身的不足。

例如像 Spring 社區(qū)因此開(kāi)發(fā)了 AOT Engine[4]如下圖 6 所示來(lái)幫助解決 Spring 項(xiàng)目對(duì)其中的反射,動(dòng)態(tài)代理等內(nèi)容進(jìn)行靜態(tài)分析處理并將其轉(zhuǎn)換為 Substrate VM 能在編譯階段可識(shí)別的內(nèi)容,確保對(duì) Spring 應(yīng)用可基于 Substrate VM 順利完成靜態(tài)編譯。

圖片

圖 6:Spring AOT Engine

在靜態(tài)分析完成后,基于靜態(tài)分析結(jié)果的可達(dá)函數(shù)列表,調(diào)用上文介紹的 GraalVM 中的 GraalVM JIT Compiler 編譯器將應(yīng)用程序編譯為與目標(biāo)平臺(tái)強(qiáng)相關(guān)的本地代碼以完成編譯過(guò)程。

編譯完成后,就會(huì)進(jìn)入到上圖 5 右側(cè) Native 可執(zhí)行文件生成階段。在該過(guò)程中,Substrate VM 會(huì)將靜態(tài)編譯階段確定和初始化的內(nèi)容以及跟 Substrate VM 運(yùn)行時(shí)以及 JDK 庫(kù)中的數(shù)據(jù)一起保存到最終可執(zhí)行文件的 Image Heap 中。其中 Substrate VM 運(yùn)行時(shí)就為最終可執(zhí)行文件提供了運(yùn)行過(guò)程中所需的垃圾回收、異常處理等能力。對(duì)于垃圾回收這塊,在一開(kāi)始的 GraalVM 社區(qū)版中僅提供了 Serial GC。企業(yè)版中提供了能力更強(qiáng)的 G1 GC。不過(guò)在最新的社區(qū)版中 GraalVM 團(tuán)隊(duì)也引入了 G1 GC[5]以便為廣大開(kāi)發(fā)者提供更強(qiáng)大的靜態(tài)編譯使用能力。

適配 GraalVM 靜態(tài)編譯

上節(jié),簡(jiǎn)單介紹了靜態(tài)編譯技術(shù)以及其本身的局限性以后,很多外部社區(qū)開(kāi)發(fā)者這時(shí)可能會(huì)疑問(wèn),一個(gè) Java 開(kāi)源項(xiàng)目如何快速進(jìn)行靜態(tài)編譯適配?對(duì)于這個(gè)問(wèn)題,其實(shí)最核心要解決的本質(zhì)問(wèn)題就是將開(kāi)源框架中的 GraalVM 無(wú)法識(shí)別和處理的動(dòng)態(tài)內(nèi)容轉(zhuǎn)換為其可識(shí)別的內(nèi)容即可。因此該問(wèn)題由于不同框架情況不一樣,因此解決方式也會(huì)有一些差異。例如在 Spring 中,針對(duì)其自身框架開(kāi)發(fā)的 AOT Engine 可以解決其框架提供的通過(guò) @Configuration 注解注冊(cè)類(lèi)初始化過(guò)程無(wú)法在靜態(tài)編譯階段被識(shí)別、提前在靜態(tài)編譯期生成原本在運(yùn)行階段才能生成的動(dòng)態(tài)代理類(lèi)解決直接靜態(tài)編譯代理類(lèi)無(wú)法被有效生成等問(wèn)題[6]從而實(shí)現(xiàn) Spring 應(yīng)用的靜態(tài)編譯適配。

對(duì)于很多基于 Spring 實(shí)現(xiàn)的開(kāi)源框架,如果本身無(wú)法被 GraalVM 識(shí)別的動(dòng)態(tài)特性都是由于 Spring 標(biāo)準(zhǔn)的那一套用法所導(dǎo)致,由于自身屬于 Spring 體系,靜態(tài)編譯過(guò)程就肯定少不了 Spring AOT Engine 的參與,因此,框架自身就不需要再提供任何適配就可以具備靜態(tài)編譯能力。

對(duì)于非 Spring 體系項(xiàng)目或者自身使用了一些 JDK 中原生的反射或者其他 Java 動(dòng)態(tài)特性,針對(duì)自身代碼中的 Java 動(dòng)態(tài)用法需要在項(xiàng)目中提供對(duì)應(yīng)的靜態(tài)配置文件才能在靜態(tài)編譯過(guò)程中讓編譯器識(shí)別其中的動(dòng)態(tài)特性,對(duì)其進(jìn)行編譯構(gòu)建才能實(shí)現(xiàn)項(xiàng)目的順利編譯與執(zhí)行。針對(duì)這種情況,GraalVM 提供了一個(gè)名叫 native-image-agent 的 Tracing Agent 來(lái)幫助大家更方便地收集元數(shù)據(jù)并準(zhǔn)備配置文件。該 Agent 會(huì)在常規(guī) Java VM 上的應(yīng)用程序運(yùn)行過(guò)程中自動(dòng)收集其中的動(dòng)態(tài)特性使用情況并將其轉(zhuǎn)換為 GraalVM 可以識(shí)別的配置文件。最后,將通過(guò) Agent 生成的框架自身的動(dòng)態(tài)配置文件存放在項(xiàng)目的:META-INF/native-image/<group.id>/<artifact.id> 目錄下,就可以在靜態(tài)編譯過(guò)程中根據(jù)這些配置內(nèi)容,識(shí)別項(xiàng)目包中的動(dòng)態(tài)特性。

Spring Cloud Alibaba 2022.0.0.0 版本所包含的所有中間件客戶(hù)端目前已完成了構(gòu)建 GraalVM 原生應(yīng)用的適配。由于項(xiàng)目自身的特定,項(xiàng)目整體實(shí)現(xiàn)中有大量的 Spring 語(yǔ)法導(dǎo)致的無(wú)法被 GraalVM 識(shí)別的動(dòng)態(tài)特性用法,這塊內(nèi)容直接交由 Spring AOT Engine 來(lái)進(jìn)行解決,社區(qū)未做額外適配工作。

除了 Spring 體系語(yǔ)法,項(xiàng)目本身還是有一些其他 Java 動(dòng)態(tài)用法的,這塊社區(qū)通過(guò) native-image-agent 來(lái)進(jìn)行解析與動(dòng)態(tài)配置生成。

基于靜態(tài)編譯構(gòu)建微服務(wù)

Spring Cloud Alibaba 2022.0.0.0 版本所包含的所有中間件客戶(hù)端已完成了構(gòu)建 GraalVM 原生應(yīng)用的適配。為用戶(hù)提供了開(kāi)箱即用的靜態(tài)編譯能力。相關(guān)功能體驗(yàn)過(guò)程如下:

環(huán)境準(zhǔn)備

首先需要在首先在機(jī)器上安裝 GraalVM 發(fā)行版。您可以在 Liberica Native Image Kit 頁(yè)面上手動(dòng)下載它,也可以使用像 SDKMAN! 這樣的下載管理器。本文演示環(huán)境為 MacOS,如果是 Windows 可參考相應(yīng)文檔[7]進(jìn)行操作。執(zhí)行以下命令安裝 GraalVM 環(huán)境:

$ sdk install java 22.3.r17-nik
$ sdk use java 22.3.r17-nik

通過(guò)檢查 java -version 的輸出來(lái)驗(yàn)證是否配置了正確的版本:

$ java -version
openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode)

應(yīng)用構(gòu)建

要使用 GraalVM 靜態(tài)編譯能力構(gòu)建微服務(wù),首先確保您項(xiàng)目的 Spring Boot 版本為 3.0.0 或以上,Spring Cloud 版本為 2022.0.0 或以上。然后在項(xiàng)目中引入 Spring Cloud Alibaba 2022.0.0.0 版本的所需模塊依賴(lài)即可。

通過(guò)以下命令生成應(yīng)用中反射、序列化和動(dòng)態(tài)代理所需的 Hints 配置文件,前提是應(yīng)用中引入了 spring-boot-starter-parent 父模塊:

$ mvn -Pnative spring-boot:run

之后應(yīng)用會(huì)啟動(dòng),進(jìn)行預(yù)執(zhí)行,需要盡可能完整的測(cè)試一遍應(yīng)用的所有功能,保證應(yīng)用的大部分代碼都被測(cè)試用例覆蓋,該過(guò)程會(huì)基于 GraalVM 的 native-image-agent 收集程序中的動(dòng)態(tài)特性,這樣可以確保完整生成應(yīng)用運(yùn)行過(guò)程中的所有必須的動(dòng)態(tài)屬性。運(yùn)行完所有測(cè)試用例后,我們發(fā)現(xiàn) resource/META-INF/native-image 目錄下會(huì)生成以下一些 hints 文件:

  • resource-config.json:應(yīng)用中資源 hint 文件
  • reflect-config.json:應(yīng)用中反射定義 hint 文件
  • serialization-config.json:應(yīng)用中序列化內(nèi)容 hint 文件
  • proxy-config.json:應(yīng)用中 Java 代理相關(guān)內(nèi)容 hint 文件
  • jni-config.json:應(yīng)用中 Java Native Interface(JNI)內(nèi)容 hint 文件

注意事項(xiàng):Spring Cloud Alibaba 2022.0.0.0 正式版本所有核心模塊都已經(jīng)默認(rèn)將自身組件相關(guān)動(dòng)態(tài)特性所需的配置內(nèi)容都包含在了依賴(lài)中,因此上述預(yù)執(zhí)行過(guò)程主要為了掃描應(yīng)用自身業(yè)務(wù)代碼以及其他第三方包中的動(dòng)態(tài)特性,以便后續(xù)靜態(tài)編譯過(guò)程能順利進(jìn)行,應(yīng)用能正常啟動(dòng)。

靜態(tài)編譯

以上步驟一切準(zhǔn)備就緒后,通過(guò)以下命令來(lái)構(gòu)建原生鏡像:

$ mvn -Pnative native:compile

成功執(zhí)行后,我們?cè)?/target 目錄可以看到生成的可執(zhí)行文件。

程序運(yùn)行

與普通可執(zhí)行文件無(wú)異,通過(guò) target/xxx 啟動(dòng)應(yīng)用, 可以觀察到類(lèi)似如下的輸出:

2023-08-01T17:21:21.006+08:00  INFO 65431 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-08-01T17:21:21.008+08:00  INFO 65431 --- [           main] c.a.cloud.imports.examples.Application   : Started Application in 0.553 seconds (process running for 0.562)

采用 GraalVM 靜態(tài)編譯技術(shù)的新版本 Spring Cloud Alibaba 應(yīng)用,所有核心能力在啟動(dòng)速度和內(nèi)存占用率方面如下表所示都有顯著改善。

圖片圖片

說(shuō)明:上述測(cè)試代碼樣例來(lái)自 Spring Cloud Alibaba 項(xiàng)目中的 examples 模塊,4c16g Mac 環(huán)境,每組數(shù)據(jù)測(cè)試 3 次取平均,具體數(shù)據(jù)因機(jī)器不同可能會(huì)有差異。

相關(guān)鏈接:

[1] Java 程序的啟動(dòng)過(guò)程分析

https://shipilev.net/talks/j1-Oct2011-21682-benchmarking.pdf

[2] GraalVM 開(kāi)源高性能多語(yǔ)言運(yùn)行時(shí)平臺(tái)

https://www.oracle.com/java/graalvm/

[3] 外部配置

https://www.graalvm.org/latest/reference-manual/native-image/metadata/

[4] AOT Engine

https://spring.io/blog/2021/12/09/new-aot-engine-brings-spring-native-to-the-next-level

[5] G1 GC

https://medium.com/graalvm/a-new-graalvm-release-and-new-free-license-4aab483692f5

[6] 動(dòng)態(tài)代理類(lèi)等問(wèn)題

https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.introducing-graalvm-native-images.understanding-aot-processing

[7] 相應(yīng)文檔

https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311

責(zé)任編輯:龐桂玉 來(lái)源: 阿里巴巴中間件
相關(guān)推薦

2017-11-22 13:01:03

Go技術(shù)棧構(gòu)建

2021-12-29 08:30:48

微服務(wù)架構(gòu)開(kāi)發(fā)

2017-08-07 08:41:13

Java微服務(wù)構(gòu)建

2024-10-10 08:34:34

事務(wù)外包模式

2018-12-03 08:00:00

微服務(wù)gRPC

2020-02-17 16:28:49

開(kāi)發(fā)技能代碼

2022-09-05 08:00:00

Java微服務(wù)AuraDB

2023-06-01 15:14:55

架構(gòu)Python微服務(wù)

2020-08-14 09:27:50

微服務(wù)容器架構(gòu)

2017-06-26 09:06:10

Spring Clou微服務(wù)架構(gòu)

2021-07-07 10:21:26

技術(shù)

2017-09-04 16:15:44

服務(wù)網(wǎng)關(guān)架構(gòu)

2020-12-10 08:00:00

開(kāi)發(fā).NET工具

2018-09-12 09:00:00

數(shù)據(jù)庫(kù)Redis微服務(wù)

2018-03-26 04:53:46

Serverless微服務(wù)架構(gòu)

2022-08-22 07:26:32

Node.js微服務(wù)架構(gòu)

2022-10-10 08:00:00

微服務(wù)Spring Boo容器

2017-12-20 15:37:39

Spring Clou微服務(wù)架構(gòu)

2018-04-23 14:31:02

微服務(wù)GraphQLBFF

2014-03-25 14:21:18

WebSocket實(shí)時(shí)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)