螞蟻金服輕量級類隔離框架概述 | SOFAArk 源碼解析

本篇開始將正式啓動 <SOFAArk:Lab/> 源碼共建系列,在此對長期以來對 SOFAStack 關注的朋友表示感謝。

本文爲《剖析 | SOFAArk 實現原理》第一篇,本篇作者衛恆,SOFAArk 開源負責人。《剖析 | SOFAArk 實現原理》系列由 SOFA 團隊和源碼愛好者們出品,項目代號:<SOFA:ArkLab/>,文末附共建列表,歡迎領取共建~


在大型軟件開發過程中,通常會推薦底層功能插件化、業務功能模塊化的開發模式,以期達到低耦合、高內聚、功能複用的優點。對於模塊化,從語言層面,原計劃在 Java7 就有的模塊化特性,終於在 Java9 裏面提供了。在 Java語言級對模塊化提供支持之前,業界內最知名的 Java 模塊化規範當屬 OSGi 了,直至到今天,OSGi 在衆多企業、廠商中被廣泛使用,比如我們常用的 Web 應用服務器、Eclipse 等均採用了 OSGi 規範。

螞蟻金服內部,CE 作爲使用了 10 年的"元老級"容器組件,見證了和支撐了每年的大促、新春紅包等流量場景。作爲中間件的常青樹,CE 以足夠的穩定性爲業務保駕護航。CE 容器也是基於 OSGi 實現了模塊化,但是由於 CE 揹負了太多包袱,使得其自身變得太重,在雲原生及商業化輸出上逐漸失去了優勢。

從 2016 年底開始,框架組內部開始在 CE 的基礎上進行抽離和整合,開始擁抱新的輕量級類隔離容器框架-SOFAArk。截止 2019 年底,SOFAArk 已經在螞蟻金服內部 Serverless 場景下落地實踐,並已經有數家企業在生產環境使用 SOFAArk ,包括網易雲音樂、挖財、溢米教育等。

SOFAArk 簡介

SOFAArk 是一款基於 Java 實現的輕量級類隔離容器,主要提供類隔離和應用(模塊)合併部署能力,由螞蟻金服公司開源貢獻。SOFAArk 提供了一套較爲規範化的插件化、模塊化的開發方案,產品能力主要包括:

  • 定義類加載模型,運行時底層插件、業務應用(模塊)之間均相互隔離,單一插件和應用(模塊)由不同的 ClassLoader 加載,可以有效避免相互之間的包衝突,提升插件和模塊功能複用能力;

  • 定義插件開發規範,提供 maven 打包工具,簡單快速將多個二方包打包成插件(Ark Plugin,以下簡稱 Plugin)

  • 定義模塊開發規範,提供 maven 打包工具,簡單快速將應用打包成模塊 (Ark Biz,以下簡稱 Biz)

  • 針對 Plugin、Biz 提供標準的編程界面,包括服務、事件、擴展點等機制

  • 支持多 Biz 的合併部署,開發階段將多個 Biz 打包成可執行 Fat Jar,或者運行時使用 API 或配置中心(Zookeeper)動態地安裝卸載 Biz。


SOFAArk:https://github.com/sofastack/sofa-ark

應用場景

基於模塊化及模塊的動態能力,SOFAArk 有非常豐富的落地場景,如:通過從 classloader 層面解決 依賴衝突問題、基於 arkcontainer 的多應用合併部署,基於動態 biz 的 SOFAServerless 等等。

依賴衝突

日常使用 Java 開發,常常會遇到包依賴衝突的問題,尤其當應用變得臃腫龐大,包衝突的問題也會變得更加棘手,導致各種各樣的報錯,例如 LinkageError、NoSuchMethodError 等;實際開發中,可以採用多種方法來解決包衝突問題,比較常見的是類似 Spring Boot 的做法,統一管理應用所有依賴包的版本,保證這些三方包不存在依賴衝突;這種做法只能有效避免包衝突問題,不能根本上解決包衝突的問題;如果某個應用的確需要在運行時使用兩個相互衝突的包,例如 protobuf2 和 protobuf3,那麼類似 Spring Boot 的做法依然解決不了問題。

爲了徹底解決包衝突的問題,需要藉助類隔離機制,使用不同的 ClassLoader 加載不同版本的三方依賴,進而隔離包衝突問題; OSGi 作爲業內最出名的類隔離框架,自然是可以被用於解決上述包衝突問題,但是 OSGi 框架太過臃腫,功能繁雜;爲了解決包衝突問題,引入 OSGi 框架,有牛刀殺雞之嫌,且反而使工程變得更加複雜,不利於開發。

SOFAArk 採用輕量級的類隔離方案來解決日常經常遇到的包衝突問題,在螞蟻金服內部服務於整個 SOFABoot 技術體系,彌補 Spring Boot 沒有的類隔離能力。SOFAArk 提出了一種特殊的包結構 – Ark Plugin,在遇到包衝突時,用戶可以使用 Maven 插件將若干衝突包打包成 Plugin,運行時由獨立的 PluginClassLoader 加載,從而解決包衝突。

假設如下場景,如果工程需要引入兩個三方包:A 和 B,但是 A 需要依賴版本號爲 0.1 的 C 包,而恰好 B 需要依賴版本號爲 0.2 的 C 包,且 C 包的這兩個版本無法兼容:

cab8e591-9584-433a-8409-0540c506bc8d.png

此時,即可使用 SOFAArk 解決該依賴衝突問題;只需要把 A 和版本爲 0.1 的 C 包一起打包成一個 Ark 插件,然後讓應用工程引入該插件依賴即可。

合併部署

複雜項目通常需要跨團隊協作開發,各自負責不同的組件,而衆所周知,協調跨團隊合作開發會遇到不少問題;比如各自技術棧不統一導致的依賴衝突,又比如往同一個 Git 倉庫提交代碼常常導致 merge 衝突。因此,如果能讓每個團隊將負責的功能組件當成一個個單獨的應用開發,運行時合併部署,通過統一的編程界面交互,那麼將極大的提升開發效率及應用可擴展性。SOFAArk 提出了一種特殊的包結構 - Ark Biz,用戶可以使用 Maven 插件將應用打包成 Biz,允許多 Biz 在 SOFAArk 容器之上合併部署,並通過統一的編程界面交互。

在開發階段,應用可以將其他應用打成的 Biz 包通過 Maven 依賴的方式引入,而當自身被打成可執行 Fat Jar 時,可以將其他應用 Biz 包一併打入,啓動時,則會根據優先級依次啓動各應用。每個 Biz 使用獨立的 BizClassLoader 加載,不需要考慮相互依賴衝突問題,Biz 之間則通過 SofaService / SofaRefernece JVM 服務進行交互。

34280f08-9db0-4203-8ee5-6666a068e8aa.png

靜態合併部署是將多個應用打包在一個 ARK 可執行 JAR 包中,然後通過 java -jar 啓動,這種方式可以在 ARK 容器內同時運行多個應用,對於一些資源要求不高、流量較少的應用可以使用這種方式部署以節省資源。


動態模塊


模塊是 ark biz 在動態模型場景下的一種別名,其實質就是一個 ark biz 包。


動態模塊相對於靜態合併部署最大的不同點是,運行時通過 API 或者配置中心(Zookeeper)來控制 Biz 的部署和卸載。動態模塊的設計理念圖如下:

9de5a6f1-5bca-4a18-b860-4660558b5a29.png

無論是靜態合併部署還是動態模塊都會有宿主應用(master biz)的概念, 如果 Ark 包只打包了一個 Biz,則該 Biz 默認成爲宿主應用;如果 Ark 包打包了多個 Biz 包,需要配置指定宿主應用。宿主應用不允許被卸載,一般而言,宿主應用會作爲流量入口的中臺系統,具體的服務實現會放在不同的動態 Biz 中,供宿主應用調用。宿主應用可以使用 SOFAArk 提供的客戶端 API 實現動態應用的部署和卸載。除了 API, SOFAArk 提供了 Config Plugin,用於對接配置中心(目前支持 Zookeeper),運行時接受動態配置;Config Plugin 會解析下發的配置,控制動態應用的部署和卸載。

動態模塊下發模型

SOFAArk 的模塊下發是動態合併部署能力的核心基礎,目前 SOFAArk 除了自身提供的 telnet 服務可用於動態管理 ark biz 之外,SOFAStack 官方社區還提供了基於 Zookeeper 做爲配置中心下發的實現,通過與 SOFADashboard 的集成,構成了一條完成的模塊下發鏈路:


7f5f68c9-8b8a-4c5f-95bf-7f9b65e6b31f.png

更多細節可以參考:SOFADashboard-SOFAArk 管控 。


SOFADashboard 作爲面向操作人員的運維管控端,可以對模塊進行動態的安裝、卸載、切換等運維操作,這些操作指令會從 SOFADashboard 下發“命令型”轉換成“狀態型”指令存儲到 Zookeeper。業務的宿主應用中可以通過引入 dashboard client,來對 Zookeeper 進行監聽,在狀態發生變更時,通過 dashboard client 提供的 api 來執行具體的運維指令。

當然,如果用戶不想依賴 Zookeeper 作爲配置中心來下發指令,也可以通過自定義 Config Plugin 的方式提供其他的下發模式,比如基於 Apollo、基於 Rest 等等。

場景案例

對於“千人千面”一詞,相信大家都不陌生,可以說任何一個電商系統的商品頁或者一個推送信息流的 APP,展示給不同用戶的商品或者信息都是不同的。

這就是動態模塊可行的典型場景之一,平臺可以根據不同的用戶、時間、事件、熱點話題等等,來向用戶提供不同的商品或者信息。


d38ab0a0-b165-4f3a-8b12-378127a92203.png

“源信息”對於系統來說是不可控制的,但是計算策略是可以的;在固有的“源信息”的基礎的情況下,可以通過調整不同的計算策略來實現將最新、最熱點或者最合適的信息展示給用戶。

對於一些普通場景來說,可以通過準備好一個推薦策略算法庫,運行時通過配置中心動態切換,來實現動態調整;當然這種在某些場景下是 OK 的,但是如果希望在此之外想去動態增加額外的推薦策略來適應當前最新的信息流呢?

動態模塊通過輕量級的類隔離+動態裝載的能力爲這種場景提供了一種可行的方案。

歡迎參加 SOFAArk 源碼解析

作爲源碼解析系列的第一篇文章,本文對 SOFAArk、 SOFAArk 使用場景以及螞蟻金服內部基於 SOFAArk 對於 Serverless 框架的的探索實踐做了簡單的介紹。對於其內部更多的概念及實現機制,希望可以通過此係列文章讓大家對 SOFAArk 有更加深刻的認識,並且能夠在實際的工作中用以解決實際的問題。同時也希望大家能夠參與我們源碼共建系列及社區共建。

同時,我們開啓了《剖析 | SOFAArk 源碼》系列,會逐步詳細介紹各個部分的代碼設計和實現,預計按照如下的目錄進行:

  • 【已完成】輕量級類隔離框架 SOFAArk 簡介

  • 【已認領】SOFAArk 容器模型解析

  • 【已認領】SOFAArk 類加載模型機制解析

  • 【已認領】SOFAArk 合併部署能力解析

  • 【已認領】SOFAArk SPI 機制和 ClassLoaderHook 機制解析

  • 【待認領】SOFAArk 動態配置機制解析

  • 【待認領】SOFAArk maven 打包插件解析

  • 【待認領】(實踐)SOFAArk 插件化機制解析與實踐

  • 【待認領】(實踐)SOFAServerless POC 實踐


如果有同學對以上某個主題特別感興趣的,可以留言討論,我們會適當根據大家的反饋調整文章的順序,謝謝大家關注 SOFAStack,關注 SOFAArk,我們會一直與大家一起成長的。

領取方式

直接回復【金融級分佈式架構】公衆號想認領的文章名稱,我們將會主動聯繫你,確認資質後,即可加入,It's your show time!

除了源碼解析,也歡迎提交 issue 和 PR:

SOFAArk:https://github.com/sofastack/sofa-ark


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章