天天看點

開源 | SOFABoot 類隔離原理剖析

原創聲明:本文系作者原創,謝絕個人、媒體、公衆号或網站未經授權轉載,違者追究其法律責任。

SOFABoot 是螞蟻金服中間件團隊開源的基于 Spring Boot 的一個開發架構,其在 Spring Boot 基礎能力之上,增加了類隔離能力,以更好地解決随着工程應用變得臃腫龐大後帶來的包沖突問題。類隔離能力天生帶來子產品化能力,同樣給協作開發帶來便利。

SOFABoot 的類隔離能力借助單獨的元件 SOFAArk 實作,遵循 Spring Boot 依賴即服務的思想,隻要工程中引入了 SOFAArk 元件依賴,類隔離能力即生效。

在上一篇文章 《在 Spring Boot 中內建 SOFABoot 類隔離能力》中,我們詳細介紹了 SOFABoot 類隔離能力的使用背景及其使用方式。本文将介紹 SOFABoot 類隔離元件 SOFAArk 的實作原理。

了解 SOFAArk 三要素

SOFAArk 類隔離架構定義了三個概念,Ark Container,Ark Plugin,Ark Biz。

在介紹這三個主角之前,我們先來介紹另一個管家:Ark 包。我們都知道一個标準的 Spring Boot 應用可以借助 Spring 官方提供的打包插件:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>           

将應用打包成一個可執行 FatJar。相對應的,Ark 包則是 SOFABoot 官方提供的打包插件:

<plugin>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofa-ark-maven-plugin</artifactId>
</plugin>           

将應用打包成一個具有類隔離能力的可執行 FatJar,稱之為 Ark 包。下圖是粗略地對比兩者的目錄結構差别:

開源 | SOFABoot 類隔離原理剖析

可以看到 Ark 包作為應用部署包的分發格式,它包含有 Ark Container,Ark Plugin 和 Ark Biz 三種格式子產品。這裡我們不對 Ark 包或者其他格式子產品的目錄結構作分析,感興趣的同學可以點開文末附上的相關連結。我們重點介紹這三個角色的功能。

  • Ark Container: Ark 容器,是元件 SOFAArk 的核心,運作 Ark 包時,Ark 容器會最先啟動,負責應用運作時的管理,主要包括建構 Ark Plugin 和 Ark Biz 的類導入導出關系表、啟動并初始化 Ark Plugin 和 Ark Biz、管理 Ark Plugin 服務的釋出和引用等等。
  • Ark Plugin: SOFAArk 定義的一種子產品格式,由若幹個 Jar 包組成的一個 FatJar,開發人員可以借助官方提供的 maven 打包插件将若幹 Jar 包打包成一個 Ark Plugin 供應用依賴。運作時,由獨立的類加載器加載,是以有隔離需求的 Jar 包建議打包成 Ark Plugin 供應用依賴。
  • Ark Biz: SOFAArk 定義的一種子產品格式,是應用及其依賴的所有三方包組成的一個 FatJar,需要注意的是,Ark Biz 不會包含應用依賴的 Ark Plugin。運作時,Ark Biz由獨立的類加載器加載,借助類導入導出關系表,Ark Biz 可以使用 Ark Plugin 的導出類和資源。

SOFAArk 運作時隔離

根據上一節的描述可以知道 SOFABoot 類隔離關鍵是了解 SOFAArk 定義的三個概念,Ark Container,Ark Plugin 和 Ark Biz。下圖表示的是應用啟動後,運作時 Ark Container,Ark Plugin,Ark Biz 的邏輯分層圖:

開源 | SOFABoot 類隔離原理剖析

我們将先以 Ark Plugin 入手來介紹 SOFABoot 類隔離的實作原理。

Ark Plugin 隔離

開發者借助 SOFABoot 官方提供的插件:

<plugin>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofa-ark-plugin-maven-plugin</artifactId>
</plugin>           

可以将 Java 子產品打包成一個 Ark Plugin,這裡我們不讨論該打包插件的配置參數和使用方式,感興趣的同學可以點開文末附上的相關連結以及學習 SOFABoot 類隔離能力使用篇。隻需要知道,Ark Plugin 主要包含元資訊有:插件啟動器、導出類、導入類、導出資源、導入資源、優先級等,這些元資訊儲存在 Ark Plugin 中的 META-INF/MANIFEST.MF 中,一份典型的 MANIFEST.MF 檔案樣式如下:

Manifest-Version: 1.0
groupId: com.alipay.sofa
artifactId: sample-ark-plugin
version: 0.3.0-SNAPSHOT
priority: 1000
pluginName: sample-ark-plugin
activator: com.alipay.sofa.ark.sample.activator.SamplePluginActivator
import-packages: 
import-classes: 
import-resources: 
export-packages: com.alipay.sofa.ark.sample.common.*,com.alipay.sofa.ark.sample
export-classes: com.alipay.sofa.ark.sample.facade.SamplePluginService
export-resources: Sample_Resource_Exported           

在上面我們提到,運作 Ark 包時,類隔離容器 Ark Container 會最先啟動,然後 Ark Container 會接管整個應用的啟動過程。針對 Ark Plugin 處理邏輯如下:

首先解析 Ark 包中引入的所有 Ark Plugin,讀取插件元資訊,建構類/資源導入導出關系索引表。

提前生成所有插件類加載器,每個 Ark Plugin 都使用獨立的類加載器,管理插件類加載邏輯,借助第一步生成的類導入導出關系表,突破 Java 原生的雙親委派模型,可以委托其他插件加載所需類,建構一個類 OSGi 的網狀類加載模型。

根據插件優先級,依次調用插件啟動器。在插件啟動器中,插件開發者可以向容器注冊服務以友善其他插件引用,也可以引用其他插件釋出的服務,及插件啟動所需的初始化操作。

需要明确一點,為了讓類加載模型足夠簡單,Ark 容器在啟動任何插件前,會把所有的插件類加載器提前建構完畢。Ark Plugin 可以互相委托加載,插件優先級隻是影響插件的啟動順序,而且也不強制要求每個 Ark Plugin 都要有啟動器。

啟動完所有插件後,Ark Container 則開始負責啟動 Ark Biz 子產品。

Ark Biz 隔離

Ark Container 在完成 Ark Plugin 的隔離和啟動後,則開始準備 Ark Biz 的隔離和啟動。

在上文中提到,應用打成 Ark 包後,Ark 包會包含 Ark Plugin 子產品和 Ark Biz 子產品。實際上 Ark Biz 其實就是應用及其所有的三方依賴打成的 FatJar 包,Ark Biz 不會包含應用引入的 Ark Plugin。開發者借助 SOFABoot 官方提供的插件:

<plugin>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofa-ark-maven-plugin</artifactId>
</plugin>           

可以将 Java(Spring Boot) 應用打包成一個 Ark Biz,這裡我們不讨論該打包插件的配置參數和使用方式,感興趣的同學可以點開文末附上的相關連結以及學習 SOFABoot 類隔離能力使用篇。隻需要知道,Ark Biz 主要包含元資訊有:應用啟動入口、禁止導入類、禁止導入資源等。這些元資訊儲存在 Ark Biz 中的 META-INF/MANIFEST.MF 中,一份典型的 MANIFEST.MF 檔案樣式如下:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.2.5
Build-Jdk: 1.8.0_101
Built-By: qilong.zql
Ark-Biz-Name: sofa-ark-sample-springboot-ark
deny-import-resources:
deny-import-packages:
deny-import-classes:
Main-Class: com.alipay.sofa.ark.sample.springbootdemo.SpringbootDemoApplication           

Ark Biz 和 Ark Plugin 有很大的不同,最明顯的則是 Ark Biz 單向依賴 Ark Plugin,即 Ark Biz 隻能單向委托 Ark Plugin 加載類和資源,反之則不可以。實際上在運作時,Ark Biz 是運作在 Ark Plugin 之上,Ark Container也是先啟動所有 Ark Plugin 然後啟動 Ark Biz。預設情況下,Ark Plugin 導出的所有類和資源都能被 Ark Biz 委托加載到,為了友善應用開發者能夠自主要制類加載邏輯,允許在打包插件中配置禁止導入類和禁止導入資源,如此,對于配置的類和資源, Ark Biz 能夠優先加載内部包含的類,而不會委托給 Ark Plugin 加載。Ark Container 針對 Ark Biz 處理邏輯如下:

首先解析 Ark 包中 Ark Biz 子產品,讀取元資訊,建構類/資源導入導出關系索引表。

生成 Ark Biz 類加載器,管理 Ark Biz 類加載邏輯,借助第一步生成的類導入導出關系表,突破 Java 原生的雙親委派模型,可以委托 Ark Plugin 加載所需類和資源。

調用應用啟動入口,啟動應用。

如此,Ark 包即完成整個啟動過程。

和 OSGi 對比

作為開源界早負盛名的動态子產品系統,基于 OSGi 規範的 Equinox、Felix 等同樣具備類隔離能力,然而他們更多強調的是一種程式設計模型,面向子產品化開發,有一整套子產品生命周期的管理,定義子產品通信機制以及複雜的類加載模型。作為專注于解決依賴沖突的隔離架構,SOFAArk 專注于類隔離,簡化了類加載模型,是以顯得更加輕量。

其次在 OSGi 規範中,所有的子產品定義成 Bundle 形式,作為應用開發者,他需要了解 OSGi 背後的工作原理,對開發者要求比較高。在 SOFAArk 中,定義了兩層子產品類型,Ark Plugin 和 Ark Biz,應用開發者隻需要添加隔離的 Ark Plugin 依賴,對本身的開發沒有任何影響,基本沒有開發門檻。

正在做的事

全文讀下來,你可能會産生這樣的一個疑惑:如果在應用中引入其他應用打包的 Ark Biz 會如何呢?

目前 SOFAArk 是可以啟動多個 Ark Biz 的,比較遺憾的是,現在 Ark Biz 之間沒法做到服務通信。如果你之前讀完過上一篇 SOFABoot 類隔離使用篇及這篇原理篇,你也許會發現,雖然 SOFAArk 是一個純粹的類隔離架構,但是基于 SOFAArk 之上,可以開發各具功能特色的 Ark Plugin,補充架構能力,供應用開發者按需依賴使用,比如已經推出的 SOFARPC Ark Plugin。回到上面的問題,為了解決多個 Ark Biz 合并部署的問題,我們正在開發一個新的 Ark Plugin,Jarslink2.0。

在螞蟻内部,多個應用合并部署在同一個 JVM 之上,是一件常見的事情。這樣帶來的主要優勢如下:

無關應用合并部署:有些應用在獨立部署時,互相之間沒有服務依賴,而且這些應用承擔業務體量都偏小,單獨占有一台實體機部署比較浪費資源。這些應用合并部署,能夠節省成本。

相關應用合并部署:多個應用之間存在服務依賴,獨立部署時,各應用之間使用 RPC 調用,雖然使用了分布式架構,穩定性高,但依然存在網絡抖動導緻的延時性問題。這些應用合并部署,RPC 調用轉為JVM内部調用,縮減調用開銷。

當然,作為螞蟻内部非常重要的一項技術創新,合并部署在特定的業務背景下有着更為重要的意義,也遠不止上面提到的兩點優勢,比如故障的隔離等等。

說回到 Jarslink2.0,這個 SOFABoot 官方開發的 Ark Plugin,主要是為了解決多個 Ark Biz 運作時管理問題。我們知道,每個 Java(Spring Boot) 應用,都可以通過我們的 maven 插件打包成 Ark Biz 供其他應用依賴。目前 SOFAArk 架構隻能做到隔離 Ark Biz,作為架構能力的補充,Jarslink2.0 插件專門管理多個 Ark Biz 的運作時。這裡預設每個 Ark Biz 都是一個 SOAFBoot/Spring Boot 工程,Jarslink2.0 提供的能力如下:

動态安裝、解除安裝 Ark Biz。

Ark Biz 之間使用注解和 xml 兩種形式釋出和引用 jvm 服務,解決多 Ark Biz 服務依賴問題。

Ark Biz 如果使用了 SOFARPC 能力,可以自動完成 RPC 轉 JVM 内部調用。

在這裡特别感謝方騰飛, 螞蟻内部花名 @清英 ,也是我們熟知的并發程式設計網(

http://ifeve.com/)

創始人。清英在螞蟻内部開發的 Jarslink1.0 在網商銀行已經落地使用很長一段時間,Jarslink2.0 是在 Jarslink1.0 基礎之上,結合 SOFABoot 類隔離架構,提供了更加通用的應用(子產品)隔離和通信的實作方案,敬請期待!

歡迎微網誌關注@SOFAStack 與我們互動,相關傳送門:

Ark 包目錄結構及其打包插件的使用

https://alipay.github.io/sofastack.github.io/docs/ark-jar.html

Ark Plugin 目錄結構及其打包插件的使用

https://alipay.github.io/sofastack.github.io/docs/ark-plugin.html

Ark Biz 目錄結構及其打包插件的使用

https://alipay.github.io/sofastack.github.io/docs/ark-biz.html

Ark Plugin 的工程示例

https://github.com/alipay/sofa-ark/tree/master/sofa-ark-samples/sample-ark-plugin

Spring Boot 工程使用類隔離能力

https://github.com/alipay/sofa-ark/tree/master/sofa-ark-samples/sample-springboot-ark