SOFAStack(Scalable Open Financial Architecture Stack)是螞蟻金服自主研發的金融級雲原生架構,包含了構建金融級雲原生架構所需的各個組件,是在金融場景裡錘鍊出來的最佳實踐。
本文為《剖析 | SOFAArk 實現原理》第二篇,本篇作者盲僧,來自 OYO。《剖析 | SOFAArk 實現原理》系列由 SOFA 團隊和源碼愛好者們出品,項目代號:,文末附系列共建列表,目前已完成領取。
前言
SOFAArk 是 SOFA 團隊開源的又一款扛鼎力作,它是一款基於 Java 實現的輕量級類隔離容器,主要提供類隔離和應用(模塊)合併部署的能力。
從 2016 年底開始,螞蟻金服內部開始擁抱新的輕量級類隔離容器框架-SOFAArk。截止 2019 年底,SOFAArk 已經在螞蟻金服內部 Serverless 場景下落地實踐,並已經有數家企業在生產環境使用 SOFAArk ,包括網易雲音樂、挖財、溢米教育等。
本文主要介紹下 SOFAArk Biz 包的打包插件,幫助大家更好的去理解 Biz 包的結構,也是為系列文章做好鋪墊。
SOFAArk biz 的打包插件是 sofa-ark-maven-plugin ,它可以將普通 Java 工程或者 Spring Boot 工程打包成標準格式的 Ark 包或者 Ark Biz 包,關於 Ark 包和 Ark Biz 包可以參考這裡:
- Ark 包:https://www.sofastack.tech/projects/sofa-boot/sofa-ark-ark-jar/
- Ark Biz:https://www.sofastack.tech/projects/sofa-boot/sofa-ark-ark-biz/
本文將從如下三個方面進行介紹:先對插件的使用和打包出來的產物做一個簡單介紹,然後告訴大家調試插件的方法,最後對整個插件的原理做一個流程圖和闡述。
SOFAArk :https://github.com/sofastack/sofa-ark
SOFAArk 插件使用
文中的示例代碼可以參考 我的 github
插件使用
先將 Spring Boot 的打包插件 spring-boot-maven-plugin 刪除或者註釋,然後再引入如下插件即可:
<plugin>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
執行 mvn package 命令後,將會打出如下結構的 3 個 jar 包,大家可以自行解壓這三個 jar 包,看一看裡面的具體內容,下面我們簡單分析一下:
tutorial-sofa-ark-maven-plugin-1.0.0-SNAPSHOT.jar :它是 maven 插件打出來的原生 jar 包,只包含我們寫的代碼和 manifest 文件,無特殊意義。
tutorial-sofa-ark-maven-plugin-1.0.0-SNAPSHOT-ark-biz.jar :這個 jar 包稱之為 Ark Biz 包,因為 SOFAArk 容器是支持運行多個 Ark Biz 的,所以打成這種包是為了和別的項目一起合併部署使用,另外 Ark 包裡也包含了這個。
tutorial-sofa-ark-maven-plugin-1.0.0-SNAPSHOT-ark-executable.jar :這個 jar 包稱之為 Ark 包,從字面上來看它是一個可執行的 jar 包,即意味著它是一個可以用 java-jar 命令來單獨運行的 Fat Jar,類似於我們用 Spring Boot 插件打出來的包。
後面的分析主要是圍繞 Ark 包來做講解,因為它包含了 Ark Biz 包,所以只要搞明白它是如何生成的,那麼對整個插件的原理也就基本瞭解了。
與 Spring Boot 插件對比
要想分析出 sofa-ark-maven-plugin 插件的作用,我們需要先和 Spring Boot 的插件進行對比,從打包產物上直觀的感受一下兩者的區別。
spring-boot-maven-plugin 插件
spring-boot-maven-plugin 是 SpringBoot 默認提供的打包插件,其功能就是將工程打包成一個可執行的 FATJAR。spring-boot-maven-plugin 打包產物的目錄結構如下:
├── BOOT-INF
│ ├── classes # 應用的字節碼目錄
│ └── lib # 應用所依賴的 jar 包
├── META-INF
│ ├── MANIFEST.MF # manifest 文件信息
│ └── maven # 應用的座標信息
└── org
└── springframework
└── boot
└── loader # 存放的是 Spring Boot Loader 的 class 文件
├── JarLauncher.class # Spring Boot 啟動類
├── archive
├── data
├── jar
└── util
MANIFEST.MF 文件內容:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: rrz
Start-Class: pers.masteryourself.tutorial.sofa.ark.maven.plugin.MavenP
luginApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.1.4.RELEASE
Created-By: Apache Maven 3.5.3
Build-Jdk: 1.8.0_101
Main-Class: org.springframework.boot.loader.JarLauncher
MANIFEST.MF 文件中可以看到,描述了當前 jar 的一些核心元素,包括啟動類、class 文件路徑、lib 依賴路徑、jdk 版本等等,這裡需要關注的是 Main-Class,SpringBoot 就是通過該類來引導啟動的。SOFAArk 應用也提供了類似的引導類及其自身特殊的結構,這主要就依託於 sofa-ark-maven-plugin 來完成的。
sofa-ark-maven-plugin 插件
關於 sofa-ark-maven-plugin 的使用方式可以參考官方文檔進行配置,篇幅原因,這裡不再贅述。下面就直接來看下 sofa-ark-maven-plugin 插件的打包產物及目錄結構,然後類比於 SpringBoot 的 FatJar 結構來理解 SOFAArk 中的一些概念和邏輯。
.
├── SOFA-ARK
│ ├── biz
│ │ └── tutorial-sofa-ark-maven-plugin-1.0.0-SNAPSHOT-ark-biz.jar # Ark Biz 包
│ └── container
│ └── sofa-ark-all-1.1.1.jar # sofa ark 容器提供的包
├── META-INF
│ └── MANIFEST.MF # manifest 文件信息
└── com
└── alipay
└── sofa
└── ark
├── bootstrap
│ ├── ArkLauncher.class # SOFA Ark 啟動類
├── common
│ ├── util
├── loader
│ ├── archive
│ ├── data
│ ├── jar
└── spi
├── archive
└── constant
MANIFEST.MF 文件內容:
Manifest-Version: 1.0
web-context-path: /
Archiver-Version: Plexus Archiver
Built-By: rrz
Ark-Biz-Name: tutorial-sofa-ark-maven-plugin
Sofa-Ark-Version: 1.1.1
deny-import-packages:
priority: 100
Main-Class: com.alipay.sofa.ark.bootstrap.ArkLauncher
deny-import-classes:
Ark-Container-Root: SOFA-ARK/container/
deny-import-resources:
Ark-Biz-Version: 1.0.0-SNAPSHOT
Created-By: Apache Maven 3.5.3
Build-Jdk: 1.8.0_101
兩者對比,可以發現,SOFAArk 的包結構相對於 SpringBoot 的包結構要更加多元一點,這裡主要原因在於,SOFAArk 除了提供業務 Biz 包(可以理解為 SpringBoot 的 FatJat)之外,還包括了 container,也就是 Ark 容器;這種機制帶來的好處是,業務可以將多個關聯的業務 Biz 放在一起來啟動,這樣在同一個 JVM 進程之內就可以存在多個業務模塊單元,優勢在於:
- 關聯業務的合併部署,減少機器資源開銷;
- 同一 JVM 進程之內,JVM 服務替代 RPC 服務,減少各業務單元之間的網絡通信開銷,提高性能;
另外從 MANIFEST.MF 文件中也可以發現,SOFAArk 中的啟動引導類與 SpringBoot 也是不同的,關於這部分,將會在後續的文章中逐一解析,敬請期待。下面再通過啟動順序來進一步瞭解下 FatJar 個 Ark 包之間的差異,以便大家更好的理解 ark 打包插件存在的真正意義。
PS:如果我們在打包時引入了 plugin 類型的包,那麼在 SOFA-ARK 目錄下還會有個 plugin 目錄(這裡沒有用到)。
啟動順序分析
基於上述插件部分的對比,我們再來看看官網對 SOFAArk 的定義:它是一款基於 Java 實現的輕量級類隔離容器,主要提供類隔離和應用(模塊)合併部署能力。重點是它能夠提供合併部署能力(顯然指的是 SOFA-ARK/biz 目錄允許放多個 Ark Biz 包),這是 SpringBoot FatJar 無法做到的,既然如此,那麼兩者的啟動順序也必然有差別,下面簡單探究一下。
首先分析下 Spring Boot 的啟動流程,在執行 java-jar 命令後,程序會調用 META-INFMANIFEST.MF 中定義的啟動類的 main 方法,即 org.springframework.boot.loader.JarLauncher ,然後 Spring Boot 會去構建一個 LaunchedURLClassLoader ,它是一個自定義的 ClassLoader ,利用它去加載 BOOT-INF 下的 lib 和 classes 目錄,最後會通過反射調用 Start-class 對應的啟動類,從而啟動整個業務的代碼,這裡用簡單的一張圖來描述下:
而 SOFAArk 的啟動流程呢?我們可以參考下官網給出的詳細啟動流程 ,這裡我們簡單抽象出幾個重要步驟:
顯而易見,SOFA Ark 並不是簡單的將一個 FatJar 啟動起來,在這個過程中,還包括了啟動 Ark Container 和 Ark Plugin,而正是因為 Ark Container 的存在,才使得多 biz 合併部署成為可能;下面就來揭開 ark 包的整個構建過程。
插件原理分析
搞清楚了插件的使用和作用後,我們就可以對插件的底層實現一探究竟了,下面我們通過 debug 的方式來看看 sofa-ark-maven-plugin 是如何構建 biz 包的。
Deubg Maven 插件
關於如果 debug maven 打包插件,可以參考這篇文章:http://www.glmapper.com/2019/07/23/maven-debug/。斷點位置參考下圖:
插件執行流程
maven 插件的源碼說到底就是對文件流的操作,比較枯燥無味,所以這裡準備了一個流程圖,大致分析出了 sofa-ark-maven-plugin 的整個原理,各位可根據流程圖自行對比源碼進行分析。
總結
通過上述內容的分析,我們應該瞭解了整個 sofa-ark-maven-plugin 的運行流程和原理了,無非是基於 Java 文件流的方式去生成特殊結構的 jar 包,然後通過定製化的啟動流程,使得在業務 biz 包代碼執行之前,先啟動 ark 容器,提供一系列的特殊功能,最後再啟動 biz。
歡迎參加 SOFAArk 源碼解析
《剖析 | SOFAArk 源碼》系列已經開啟,會逐步詳細介紹各個部分的代碼設計和實現,預計按照如下的目錄進行:
- 【已完成】輕量級類隔離框架 SOFAArk 簡介
- 【已完成】SOFAArk Maven 打包插件解析
- 【已認領】SOFAArk 容器模型解析
- 【已認領】SOFAArk 類加載模型機制解析
- 【已認領】SOFAArk 合併部署能力解析
- 【已認領】SOFAArk SPI 機制和 ClassLoaderHook 機制解析
- 【已認領】SOFAArk 動態配置機制解析
- 【已認領】(實踐)SOFAArk 插件化機制解析與實踐
以上目錄已經完成認領,除以上目錄涉及的內容外,如果您對 SOFAArk 的其他模塊也有想要分享的內容,歡迎您聯繫我們參與源碼解析系列共建。
參與方式
在【金融級分佈式架構】公眾號後臺留言“SOFAArkLab”,我們將會主動聯繫你,確認分享內容主題與細節,即可加入,It's your show time!
希望可以通過此係列文章讓大家對 SOFAArk 有更加深刻的認識,並且能夠在實際的工作中用以解決實際的問題,同時也歡迎大家參與社區共建,提交 issue 和 PR:
SOFAArk:https://github.com/sofastack/sofa-ark
謝謝大家關注 SOFAStack,關注 SOFAArk,我們會一直與大家一起成長。