Spring 官宣:換掉 JVM!

使用簡單mvn spring-boot:build-image或gradle bootBuildImage命令,您可以生成一個優(yōu)化的容器映像,該映像將包含一個最小的OS層和一個小的本機可執(zhí)行文件,該映像僅隨附JDK,Spring以及您在應(yīng)用程序中使用的依賴項中的必需位。
請參閱下面的示例,其中包含50MB可執(zhí)行文件的最小容器映像,其中包含Spring Boot,Spring MVC,Jackson,Tomcat,JDK和應(yīng)用程序。

具有Spring Cloud功能的無服務(wù)器 以更便宜和更可持續(xù)的方式托管Spring微服務(wù) 非常適合VMware Tanzu等Kubernetes平臺 想要創(chuàng)建最佳的容器映像來打包您的Spring應(yīng)用程序和服務(wù)
在使用場景上,比如 Piotr Mińkowski 提供了一個非常棒的指南,介紹了如何在 Knative 上使用 Spring Boot 和 GraalVM 構(gòu)建原生微服務(wù)。
阿里JVM 團隊技術(shù)專家林子熠博士在最新出版的《GraalVM與Java靜態(tài)編譯:原理與應(yīng)用》一書中,揭秘Oracle GraalVM中Java靜態(tài)編譯技術(shù)的特性、實現(xiàn)原理、應(yīng)用與調(diào)試技巧,以突破Java“冷啟動”桎梏,實現(xiàn)啟動性能“質(zhì)”的飛躍。
作者介紹?:林子熠 博士
Java 誕生至今的 25 年里,憑借其峰值性能高、語言功能強、生態(tài)支持好等特點贏得了語言市場的霸主地位。但 Java 冷啟動開銷大,而云原生時代下的應(yīng)用程序短小,啟動頻繁,冷啟動問題的解決機不容發(fā)。
下圖為典型 Java 應(yīng)用的生命周期:

如圖,Java 應(yīng)用生命周期分為 5 個階段:VM 初始化階段、APP 初始化階段、APP 初活躍階段、APP 穩(wěn)定執(zhí)行期、結(jié)束階段。
VM 初始化(圖中紅色)和 Class loading(圖中藍色)的開銷為冷啟動的根因。阿里巴巴實現(xiàn)了兩類改造:一類為改良型技術(shù),調(diào)整優(yōu)化現(xiàn)有 Java 的框架和運行模型,另外一類為革新型的技術(shù),擺脫原有 Java 框架另起爐灶。
改良型技術(shù)中,阿里巴巴主要實現(xiàn)了基于傳統(tǒng) CDS(Class Data Sharing)的 EagerAppCDS。傳統(tǒng) CDS 包括 mark、Klass*、fields 三部分,如下圖所示:
下圖為 EagerAppCDS 在阿里巴巴內(nèi)部實踐的脫敏數(shù)據(jù),如圖所示性能提升效果從 12%~95% 不等。

EagerAppCDS 雖未開源但已在阿里云 SAE(Serverless 微服務(wù) PaaS 平臺)上線。線上可公開實測數(shù)據(jù)中應(yīng)用啟動耗時降低 5%~45%,提升效果與啟動時加載類數(shù)量成正比。

除此之外,我們還實現(xiàn)了以下改進型技術(shù):
傳統(tǒng) Java 執(zhí)行模型如下圖所示:Application(應(yīng)用本身)在 libs 的支持下運行在 JDK 上在 JVM 中執(zhí)行。
靜態(tài)編譯在 Graal Compiler 編譯器中編譯 Application、libs、JDK,同時編譯 Substrate VM Runtime,獲得 Native Image。Native Image 包含 code(編譯后的代碼)和 Image heap(存儲數(shù)據(jù))兩部分。Image heap 為運行時 heap 的起點,直接讀取 Image heap 可以提高運行時的性能。
靜態(tài)編譯必須遵循封閉性原則 (the closed-world assumption),即所有運行時信息均需在編譯時可見。該原則帶來兩個基本問題:如何確定封閉的邊界?如何處理 Java 的動態(tài)特性?
Java bytecode 編譯為 Native code 時,代碼抽象性降低體積增大,如若編譯所有代碼,Native Image 體積將過于龐大,因此需確定封閉邊界。SVM 通過靜態(tài)分析上實現(xiàn)了從給定入口開始確定程序可達范圍的功能。
該技術(shù)應(yīng)用廣泛,例如 main 函數(shù)調(diào)用 Virtue call 必須先明確其 type,type 和 Virtue call 有時可唯一綁定,但通常不能唯一綁定。此時使用靜態(tài)分析技術(shù),可明確 Virtue call type 的可能范圍,實現(xiàn)封閉。

受靜態(tài)分析本身的特性和能力所限,靜態(tài)分析得到的可達代碼集合(藍色)略大于實際執(zhí)行代碼集合(綠色)。靜態(tài)分析精度越高、冗余越少、image 越小。
靜態(tài)分析無法分析出 Java 的許多動態(tài)特性運行時的行為,如反射、動態(tài)代理、JNI、序列化(阿里巴巴貢獻,從 21.0 開始支持)、動態(tài)類加載(阿里巴巴貢獻,patch 已經(jīng)通過評審)等。此時需提前獲取所需信息,方可封閉此類動態(tài)特性的觸達范圍——即需基于配置進行動態(tài)特性支持。
以反射為例。SVM 提供了 native-image-agent,可記錄 APP 運行時所有的反射。編譯時只需解析配置文件,即可注冊反射目標,擴大編譯范圍;同時獲取反射信息后可放入 ReflectionData 緩存中,將反射調(diào)用替換為直接調(diào)用。運行時如遇反射可查找 ReflectionData,獲取目標值,通過 Method.invoke 直接調(diào)用目標函數(shù)。
下圖為通過靜態(tài)編譯和傳統(tǒng) Java 兩種方式,分別用反射調(diào)用空函數(shù) 30 次性能對比測試結(jié)果:
靜態(tài)編譯由于所有的類均已被編譯因此只有一個類加載器,實際只執(zhí)行類查找功能。
傳統(tǒng) Java 一邊檢查異常一邊運行,如遇異常直接處理即可。SVM 考慮到在不同平臺兼容性,異常處理采用非信號處理機制:檢測無錯方可正常運行。該檢測對性能影響小。
此外,靜態(tài)編譯的 GC 為 Oracle 開源版本中的單線程 stop-and-copy 順序 GC,性能一般。
下圖為 Graal VM 官方的實驗數(shù)據(jù):

如上圖所示,在只執(zhí)行 Hello world 程序時,Native Image 性能次于 C,與 Go 相當,遠快于傳統(tǒng) JDK;內(nèi)存使用次于 C,只有 Go 的一半,遠低于傳統(tǒng) JDK,具有高性能低內(nèi)存占用的優(yōu)點。圖中紅色數(shù)據(jù)為受測語言數(shù)據(jù)除以 Native Image 數(shù)據(jù)所得比值。
Javac 為 Java 編寫的編譯器:可以在 Java 程序中來調(diào)用 API 編譯,也可用 stand alone 工具編譯。通過 API 調(diào)用,實際上已完成 VM 啟動,因此兩者對比可觀察冷啟動帶來的性能差異。

通過 API 調(diào)用 Javac 耗時 250ms,使用 Native Image 后耗時達到 35ms,實現(xiàn)了 1 個數(shù)量級的飛躍。


靜態(tài)編譯的局限性如上表所示:
為實現(xiàn)封閉性,反射、動態(tài)代理、JNI、序列化、動態(tài)類加載均需要通過配置支持;
不支持 InvokeDynamic(開發(fā)人員使用)、Method Handles(開發(fā)人員使用)、Security Manager、多 classloader、Finalizers、過時 Thread 函數(shù)(如 Thread.stop())等;
Java 程序被靜態(tài)編譯后不再保留 bytecode,因此存在監(jiān)控、調(diào)試方面的問題:不支持 JVMTI、JMX、agent,只能使用 GDB 調(diào)試,無法通過 Eclipse IDE、IntelliJ IDEA 等調(diào)試。
GraalVM 靜態(tài)編譯目前生態(tài)如下:
阿里云:通過阿里云函數(shù)計算平臺進行支持部署 serverless Native Image 應(yīng)用,通過 Apache RocketMQ 為 C++ 客戶端提供使用靜態(tài)編譯的 Java 共享庫;
Spring 社區(qū):發(fā)布了針對于靜態(tài)編譯 Spring-Native beta 版本,完全支持 Spring 的運算;
MICRONAUT:實現(xiàn)了支持 Native Image 的去反射微服務(wù)框架;
Facebook & Twitter:均在生產(chǎn)環(huán)境下使用 Graal 編譯器代替 C2 編譯器。
總之,在 Serverless 場景下 Java 的冷啟動問題與應(yīng)用對快速響應(yīng)、實時擴展的需求形成突出矛盾。阿里巴巴一方面在現(xiàn)有技術(shù)上不斷改進,最終形成突破:EagerAppCDS 提升最多 45% 的啟動速度;另一方面積極參與開源社區(qū)探索創(chuàng)新型的前沿技術(shù),打磨成熟用于實踐:GraalVM 靜態(tài)編譯技術(shù)最多提升百倍啟動速度。但 GraalVM 存在兼容性和改造成本的問題,適合新項目。
來源 | QCon全球軟件開發(fā)大會
嘉賓 | 林子熠? ? ?
整理 | 李慧文
熱門推薦:
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、轉(zhuǎn)發(fā)、在看。

