動態

詳情 返回 返回

如何在一個基座上安裝更多的 Koupleless 模塊? - 動態 詳情

如何在一個基座上安裝更多的 Koupleless 模塊?

文|梁櫟鵬(立蓬)

螞蟻集團技術工程師

雲原生領域工程師

就職於螞蟻集團中間件團隊,參與維護與建設螞蟻 SOFAArk 和 Koupleless 開源項目,參與內部 SOFAServerless 產品的研發和實踐。

本文2773字,預計閲讀 7 分鐘

本文屬於 Koupleless 進階系列文章第五篇,默認讀者對 Koupleless 的基礎概念、能力都已經瞭解。如果還未了解過的可以在文末​「閲讀原文」​​​查看官網(https://koupleless.io/ ​)

進階系列一:Koupleless 內核系列|模塊化隔離與共享帶來的收益與挑戰

進階系列二:Koupleless 單進程多應用如何解決兼容問題

進階系列三:Koupleless 內核系列 | 一台機器內 Koupleless 模塊數量的極限在哪裏?

進階系列四:Koupleless 可演進架構的設計與實踐|當我們談降本時,我們談些什麼

在往期文章中,我們已經介紹了 Koupleless 的收益、挑戰、應對方式及存量應用的改造成本,幫助大家瞭解到 Koupleless 是如何低成本地為業務研發提升效率和降低資源成本的。在實踐中,開發者可以將多個 Koupleless 模塊部署在同一個基座上,從而降低資源成本。那麼,如何在一個基座上安裝更多的模塊呢?

通常來説,有三種方式:模塊複用基座的類、模塊複用基座的對象、模塊卸載時清理資源。其中,最簡單、最直接、最有效的方式是讓模塊複用基座的類,即模塊瘦身

所謂模塊瘦身,就是讓模塊複用基座所有依賴的類,模塊打包構建時移除基座已經有的 Jar 依賴,從而讓基座中可以安裝更多的模塊。

在最初的模塊瘦身實踐中,模塊開發者需要感知基座有哪些依賴,並且在開發時儘量使用這些依賴,從而複用基座依賴裏的類。其次,開發者需要根據基座所有依賴,判斷哪些依賴可以移除並進行手工移除。在依賴移除後,還可能會出現以下場景:

  • 由於開發者誤判,移除了基座沒有的依賴,導致模塊編譯正常通過,而運行期出現❌​ClassNotFound、LinkageError 等錯誤​;
  • 由於模塊依賴的版本和基座不同,導致模塊編譯正常通過,而運行期出現​❌依賴版本不兼容的錯誤​。

由此,引申出了 3 個關鍵問題:

  • 模塊如何感知基座運行時的所有依賴,從而確定需要移除的依賴?
  • 如何簡單地移除依賴,降低普通應用和模塊相互轉換的改造成本?
  • 如何保證在移除模塊依賴後,模塊編譯時和模塊運行在基座中的依賴是一樣的?

下面,本文就將介紹模塊瘦身原理、原則,並針對以上三個關鍵問題給出解決方式。

模塊瘦身原理

Koupleless 底層藉助 SOFAArk 框架,實現了模塊與模塊之間、模塊和基座之間的類隔離。模塊啓動時會初始化各種對象,會優先使用模塊的類加載器去加載構建產物 FatJar 中的 class、resource 和 Jar 包,找不到的類會委託基座的類加載器去查找。

圖片

基於這套類委託的加載機制,讓基座和模塊共用的 class、resource 和 Jar 包通通下沉到基座中,可以讓模塊構建產物非常小,從而使模塊消耗的 Metaspace 非常少,基座上能安裝的模塊數量也更多,啓動也更快。

其次,模塊啓動後 Spring 上下文中會創建很多對象。如果啓用了模塊熱卸載,可能無法完全回收,且安裝次數過多會造成 Old 區、Metaspace 區開銷大,觸發頻繁 FullGC。所以需要控制單模塊包大小 < 5MB,這樣不替換或重啓基座也能熱部署熱卸載數百次。

在模塊瘦身後,能實現以下兩個好處:

  • 允許基座安裝更多的模塊數量,從而在合併部署場景下,​進一步降低資源成本​;在熱部署熱卸載場景下,不替換或重啓基座就能熱部署、熱卸載模塊更多次。
  • 提高模塊安裝的速度​,減少模塊包大小,減少啓動依賴,控制模塊安裝耗時 < 30秒,甚至 < 5秒。

模塊瘦身原則

由上文模塊瘦身原理可知,模塊移除的依賴必須在基座中存在,否則模塊會在運行期間出現 ClassNotFound、LinkageError 等錯誤。

因此,模塊瘦身的原則是,​在保證模塊功能的前提下,將框架、中間件等通用的依賴包儘量放置到基座中,模塊中複用基座的依賴。​這樣打出的模塊包會更加輕量。如圖:

圖片

關鍵一:可感知的基座運行時

在基座和模塊協作緊密的情況下,模塊應該在開發時就感知基座正使用的所有依賴,並按需引入需要的依賴,而無需指定版本。為此,我們提供了 “基座-dependencies-starter” 的打包功能,該包在中記錄了基座當前所有運行時依賴的 GAV 座標 (GAV: GroupId、ArtifactId、Version)。打包方式非常簡單,在基座的打包插件中配置必要的參數即可:

<build>
  <plugins>
    <plugin>
      <groupId>com.alipay.sofa.koupleless</groupId>
      <artifactId>koupleless-base-build-plugin</artifactId>
      <configuration>
        <!-- ... -->
        <!--生成 starter 的 artifactId(groupId和基座一致),這裏需要修改!!-->
        <dependencyArtifactId>${baseAppName}-dependencies-starter</dependencyArtifactId>
        <!--生成jar的版本號-->
        <dependencyVersion>0.0.1-SNAPSHOT</dependencyVersion>
      </configuration>
    </plugin>
  </plugins>
</build>

執行 mvn 命令:

mvn com.alipay.sofa.koupleless:koupleless-base-build-plugin::packageDependency -f ${基座 bootstrap pom 對於基座根目錄的相對路徑}

然後,模塊配置項目的 parent 為 “基座-dependencies-starter”。

<parent>
    <groupId>com.alipay</groupId>
    <artifactId>${baseAppName}-dependencies-starter</artifactId>
    <version>0.0.1</version>
</parent>

這樣一來,在模塊的開發過程中,開發者就能感知到基座運行時的所有依賴。

​關鍵二:​低成本的模塊瘦身

在應用中,最簡單的移除依賴的方式是把依賴的 scope 設置為 provided。但這種方式會增加普通應用轉換為模塊的成本,同時也意味着,如果模塊要轉為普通應用,需要將這些依賴配置回 compile,改造成本較高。

為了降低模塊瘦身的成本,我們提供了兩種配置模塊瘦身的方式:基於 “基座-dependencies-starter” 自動瘦身和基於配置文件瘦身。

基於 “基座-dependencies-starter” 自動瘦身

我們提供了基於 “基座-dependencies-starter” 的自動瘦身,自動排除和基座相同的依賴​(GAV 都相同)​,保留和基座不同的依賴。配置十分簡單,在模塊的打包插件中配置 baseDependencyParentIdentity 標識即可:

<build>
  <plugins>
    <plugin>
      <groupId>com.alipay.sofa</groupId>
      <artifactId>sofa-ark-maven-plugin</artifactId>
      <configuration>
        <!-- ... -->
        <!-- 配置 “基座-dependencies-starter” 的標識,規範為:'${groupId}:${artifactId}' -->
        <baseDependencyParentIdentity>${groupId}:${baseAppName}-dependencies-starter</baseDependencyParentIdentity>
      </configuration>
    </plugin>
  </plugins>
</build>

基於配置文件瘦身

在配置文件中,模塊開發者可以主動配置需要排除哪些依賴,保留哪些依賴。

為了進一步降低配置成本,用户僅需配置需要排除的頂層依賴,打包插件會將該頂層依賴的所有間接依賴都排除,而無需手動配置所有的間接依賴。如:

# excludes config ${groupId}:{artifactId}:{version}, split by ','
excludes=org.apache.commons:commons-lang3,commons-beanutils:commons-beanutils
# excludeGroupIds config ${groupId}, split by ','
excludeGroupIds=org.springframework
# excludeArtifactIds config ${artifactId}, split by ','
excludeArtifactIds=sofa-ark-spi

​關鍵三:​保證瘦身的正確性

如果基座運行時沒有模塊被排除的依賴,或者基座運行時中提供的依賴版本和模塊預期不一致,那麼模塊運行過程中可能會報錯。為了保證瘦身的正確性,我們需要在模塊編譯和發佈的環節做檢查。

在模塊編譯時,模塊打包插件會檢查被瘦身的依賴是否在 “基座-dependencies-starter” 中,並在控制枱輸出檢查結果,但檢查結果不影響模塊的構建結果。同時,插件允許更嚴格的檢查:配置一定參數。如果基座中不存在模塊被排除的依賴,那麼模塊構建失敗,直接報錯。

在模塊發佈時,在發佈流程中拉取基座的運行時依賴,檢查是否和 “基座-dependencies-starter” 一致。如果不一致,那麼卡住發佈流程,開發者可根據情況去升級模塊的 “基座-dependencies-starter” 或跳過該卡點。

模塊瘦身效果

以某個依賴了 16 箇中間件的模塊為例,將模塊的 parent 配置為 “基座-dependencies-starter” 自動瘦身,下表是瘦身前後的 ark-biz.jar 大小和 Metaspace 佔用的對比:

圖片

總結

通過上文相信大家已經瞭解,我們可以通過簡單的配置,讓模塊打包更小,從而在一個基座上安裝更多的 Koupleless 模塊,進一步降低資源成本。

最後,再次歡迎大家使用 Koupleless 和參與共建,我們期待您寶貴的意見!

user avatar ospo 頭像 yunxiao0816 頭像 bug1412 頭像 alixitongruanjianjishu 頭像 aipaobudezuoyeben 頭像 api7 頭像 xiejinrong 頭像
點贊 7 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.