金融級應用開發|SOFABoot 框架剖析

SOFAStack發表於2022-04-15

前言

SOFABoot 是螞蟻集團開源的基於 Spring Boot 的研發框架,提供了諸如 Readiness Check、類隔離和日誌空間隔離等能力,用於快速、敏捷地開發 Spring 應用程式,特別適合構建微服務系統。

Spring Boot 基於 Spring 的按條件配置(Conditional Configuration),結合 starter 依賴機制提供了快捷、方便開發 Spring 專案的體驗,獲得了極大的成功。

SOFABoot 在這兩個能力上基於 Spring Boot 擴充套件出適應於金融級應用開發框架。作為脫胎於螞蟻集團內部對於 Spring Boot 的實踐,SOFABoot 補充了 Spring Boot 在大規模金融級生產場景下一些不足的地方,例如 Readiness 檢查、類隔離和日誌空間隔離等等能力。在增強了 Spring Boot 的同時,SOFABoot 還提供了讓使用者可以在 Spring Boot 中方便使用 SOFAStack 中介軟體的能力。

SOFABoot :https://github.com/sofastack/sofa-boot

功能點概覽

SOFABoot 完全相容 Spring Boot,Spring Boot 技術棧可以快速切換到 SOFABoot 技術棧:修改專案 pom 依賴的 <parent/> 節點。

例如將:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${spring.boot.version}</version>
    <relativePath />
</parent>

替換為:

<parent>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofaboot-dependencies</artifactId>
    <version>${sofa.boot.version}</version>
    <relativePath />
</parent>

當前 SOFABoot 的最新版本為 v3.11.1。

應用 Readiness 檢查

一個應用啟動之後,是否“準備”好能處理外部請求呢?

作為應用流量入口的元件是否可以接收外部連線?

這就很有必要引入應用 Readiness 的檢查,SOFABoot 提供除 Spring Boot 健康檢查之外的應用的 Readiness 檢查能力,保證應用元件的正常啟動、安全上線。

SOFABoot 通過 HealthChecker 檢查各元件的 ready 情況。

在 Spring 上下文重新整理完成之後(所有的 Spring Bean 已經例項化完成),SOFABoot 會獲取 IoC 容器中所有的 HealthChecker 實現類,檢查其返回的元件健康狀況。

在應用開啟了模組化隔離之後,模組 HealthChecker 還會檢查各模組的健康狀況。Spring 原生的 HealthIndicator 作為 Readiness 的一部分也會納入 Readiness 的結果中,若 HealthIndicator 出現了失敗的情況,那麼應用的 Readiness 也是不通過。

Readiness 檢查包含元件的後置檢查,流量入口元件(例如:RPC、REST)需要保證後置檢查通過之後,能接受外部流量的請求,應用才是真正 ready 了。

應用 Readiness 與 Liveliness 的不同是:

  • Readiness 表示的是應用啟動完成之後是否“準備”好的狀態,啟動完成之後是不變的
  • 兩次部署間的 Readiness 的所有請求結果是一致的

應用模組化

應用模組化的方案多種多樣。傳統方案是以應用功能為邊界做模組劃分;研發期間,不同職責的類放在不同的模組下,但在執行期間都在同一個 classpath 下,沒有任何隔離。

而與傳統的模組劃分方案不同,人們發現可以利用 Java 的 ClassLoader 機制,將模組與模組間的類完全隔離。

當某個模組需要與另一個模組通訊時,可以通過類的匯入和匯出來實現。OSGi 和 SOFAArk 都是基於 ClassLoader 隔離的模組化實踐方案。

傳統的模組化方案沒有任何的隔離手段,模組間的邊界得不到保障,容易出現模組間的緊耦合。而基於 ClassLoader 的模組化方案則過於徹底,研發人員必須十分清楚類的匯入與匯出、Java 的類載入體系,模組劃分的負擔轉嫁到了普通研發人員身上。

SOFABoot 綜合以上兩種方案的利弊,引入了介於兩者之間的模組化方案:

每個模組有獨立的 Spring 上下文,通過上下文的隔離,讓不同模組之間的 Bean 的引用無法直接進行,達到模組在執行時的隔離。

這樣既保證了不引入過多的複雜性,也避免了沒有任何隔離措施的模組邊界保障。

如下圖所示:

所有的 SOFABoot 模組都會有一個相同的 Spring Context 的 Parent,稱之為 Root Application Context。

對於所有模組都需要引入的 Bean,可以選擇將其放置於 Root Application Context 中,在所有的模組間共享。此外,SOFABoot 框架提供兩種 Spring 上下文隔離方案後的模組間通訊能力:

  • JVM 服務的釋出和引用:同一個應用內不同模組間的通訊
// Publish a JVM service
@Component
@SofaService
public class MyServiceImpl implements MyService {
    // implementation goes here
}
// Reference a JVM service
public class AnyClass {
    @SofaReference
    private MyService myService;
}
  • RPC 服務的釋出和引用:不同應用間的通訊
// Publish a RPC service
@Component
@SofaService(interfaceType = MyService.class, bindings = { @SofaServiceBinding(bindingType = "bolt") })
public class MyServiceImpl implements MyService {
    // implementation goes here
}
// Reference a RPC service
public class AnyClass {
    @SofaReference(binding = @SofaReferenceBinding(bindingType = "bolt"))
    private MyService myService;
}

除了通過註解的方式,SOFABoot 還支援 XML 檔案和程式設計 API 的配置方式。

除了模組間通訊能力,SOFABoot 還提供:

  • Module-Profile:模組級 Profile 能力,指定模組是否啟動
  • 擴充套件點:利用 Nuxeo Runtime 為 Bean 提供擴充套件點入口
  • Require-Module:宣告模組間依賴關係

應用並行化啟動

模組並行化啟動

SOFABoot 模組之間的依賴關係可以通過 Require-Module 指定,SOFABoot 會計算模組間的依賴形成一個有向無環圖(DAG)。

SOFABoot 按照拓撲關係順序啟動依賴模組,並行啟動自由模組。

例如有如下的模組間依賴:

從圖中可知,模組 A 必須在模組 B 和 C 之前啟動,模組 D 必須在模組 E 之前啟動,模組 A 和 D 可以並行啟動(開始起點的自由模組)。相對於所有模組共享一個 Spring 上下文的應用,SOFABoot 應用的並行啟動能顯著加快應用啟動速度。

Spring Bean 非同步初始化

實際的 Spring/Spring Boot 開發中,Spring Bean 常常需要在初始化過程中執行準備操作,如拉取遠端配置、初始化資料來源等等。

並且,這些準備操作在 Bean 初始化過程中佔據了大量的時間,顯著拖慢速度 Spring 上下文重新整理速度。然而,Bean 初始化的準備操作與 Bean 的後置處理往往沒有強制的前後順序,是能夠並行的。

SOFABoot 捕捉到了這個特點,提供了可配置選項,將 Bean 的 init-method 方法的執行非同步化,從而加快 Spring 上下文重新整理過程。

如圖所示,Spring 在非同步執行自定義 init-method 方法之後,馬上進行 BeanPostProcessor 的後置處理,相當於“跳過”了最耗時的 init-method 環節。

Spring Bean 非同步初始化配置方法:

<!-- 通過將 async-init 設為 true,開啟對應 bean 的非同步化初始化 -->
<bean id="testBean" class="com.alipay.sofa.beans.TimeWasteBean" init-method="init" async-init="true"/>

中介軟體整合管理

SOFABoot 通過 starter 機制管理了中介軟體依賴。

一箇中介軟體的使用不用再引入一長串 JAR 包依賴,而只需要一個 starter 依賴,將中介軟體當作可獨立插拔的“外掛”;starter 依賴負責傳遞中介軟體需要的 JAR 包依賴。

中介軟體 starter 版本與 SOFABoot 版本關聯,並且保證這些中介軟體 starter 版本的傳遞依賴經過嚴格測試是互相相容的。不過 SOFABoot 的依賴管理依然是弱管理,如果使用者想要指定某個 JAR 包的版本,那麼也可以覆蓋 starter 中配置的版本。

SOFABoot 支援 Maven 和 Gradle 的依賴配置方式。

日誌隔離

SOFABoot 通過 sofa-common-tools 整合了日誌空間的隔離能力。

框架自動發現應用中的日誌實現,避免中介軟體和應用日誌實現的繫結。

二方包或者引入的中介軟體面向日誌程式設計介面 SLF4J 去程式設計,具體的日誌實現交給 SOFABoot 應用開發者去選擇;同時二方包或者中介軟體針對每一個日誌實現提供配置以輸出日誌到相對固定目錄下的檔案。

應用選擇的日誌實現,框架都能夠自動感知並選擇相應的配置檔案日誌輸出。

應用類隔離

SOFABoot 通過 SOFAArk 提供類隔離能力和應用合併部署能力。

SOFAArk 使用隔離的類載入模型,執行時底層外掛、業務應用之間均相互隔離,單一外掛和應用由不同的 ClassLoader 載入,可以有效避免相互之間的包衝突,提升外掛和模組功能複用能力。

支援多應用的合併部署,開發階段將多個應用打包成可執行 Fat Jar,執行時使用 API 或配置中心動態地安裝解除安裝應用。

相關文章