4.3.2 模块瘦身

Koupleless 模块瘦身

为什么要瘦身

Koupleless 底层借助 SOFAArk 框架,实现了模块之间、模块和基座之间的类隔离。模块启动时会初始化各种对象,会优先使用模块的类加载器去加载构建产物 FatJar 中的 class、resource 和 Jar 包,找不到的类会委托基座的类加载器去查找。

基于这套类委托的加载机制,让基座和模块共用的 class、resource 和 Jar 包通通下沉到基座中,可以让模块构建产物非常小,从而模块消耗的内存非常少,启动也能非常快

其次,模块启动后 Spring 上下文中会创建很多对象,如果启用了模块热卸载,可能无法完全回收,安装次数过多会造成 Old 区、Metaspace 区开销大,触发频繁 FullGC,所以需要控制单模块包大小 < 5MB。这样不替换或重启基座也能热部署热卸载数百次。

所谓模块瘦身,就是让基座已经有的 Jar 依赖不参与模块打包构建,从而实现上述两个好处:

  • 提高模块安装的速度,减少模块包大小,减少启动依赖,控制模块安装耗时 < 30秒,甚至 < 5秒
  • 在热部署热卸载场景下,不替换或重启基座也能热部署热卸载数百次

瘦身原则

构建 ark-biz jar 包的原则是,在保证模块功能的前提下,将框架、中间件等通用的包尽量放置到基座中,模块中复用基座的包,这样打出的 ark-biz jar 会更加轻量。

在不同场景下,复杂应用可以选择不同的方式瘦身。

场景及相应的瘦身方式

场景一:基座和模块协作紧密,如中台模式 / 共库模式

在基座和模块协作紧密的情况下,模块应该在开发时就感知基座的部分facade类和基座正使用的依赖版本,并按需引入需要的依赖。 模块打包时,仅打包两种依赖:基座没有的依赖,模块和基座版本不一致的依赖。

因此,需要让基座:

  1. 统一管控模块依赖版本,让模块开发时就知道基座有哪些依赖,风险前置,而且模块开发者按需引入部分依赖,无需指定版本。

需要让模块:

  1. 打包时,仅打包基座没有的依赖、和基座版本不一致的依赖,降低模块瘦身成本

步骤一 打包“基座-dependencies-starter”

目标

该步骤将打出 “基座依赖-starter”,用于统一管控模块依赖版本。

基座bootstrap pom增加配置

注意:以下配置中的 dependencyArtifactId 需要修改,一般为${baseAppName}-dependencies-starter

<build>
<plugins>
    <plugin>
        <groupId>com.alipay.sofa.koupleless</groupId>
        <artifactId>koupleless-base-build-plugin</artifactId>
        <!--        koupleless.runtime.version >= 1.3.0 -->
        <version>${koupleless.runtime.version}</version>
        <configuration>
            <!--生成 starter 的 artifactId(groupId和基座一致),这里需要修改!!-->
            <dependencyArtifactId>${baseAppName}-dependencies-starter</dependencyArtifactId>
            <!--生成jar的版本号-->
            <dependencyVersion>0.0.1-SNAPSHOT</dependencyVersion>
            <!-- 调试用,改成 true 即可看到打包中间产物 -->
            <cleanAfterPackageDependencies>false</cleanAfterPackageDependencies>
        </configuration>
    </plugin>
  </plugins>
</build>

本地测试

  1. 打包基座 dependency-starter jar:在基座根目录执行命令:
mvn com.alipay.sofa.koupleless:koupleless-base-build-plugin::packageDependency -f ${基座 bootstrap pom 对于基座根目录的相对路径} 

构建出来的 pom 在 outputs 目录下,也会自动安装至本地的 maven 仓库。

注意,该步骤不会将 “基座依赖-starter” 上传至 maven 仓库。欢迎后续讨论补充 “上传至 maven 仓库” 的方案。

步骤二 模块修改打包插件和 parent

目标

  1. 模块开发时,将步骤一中的 “基座-dependencies-starter” 作为模块项目的 parent,统一管理依赖版本;
  2. 修改模块打包插件,模块打包时只将“基座没有的依赖”、“与基座版本不一致的依赖”打包进模块,而不用手动配置“provided”,自动实现模块瘦身

模块根目录的 pom 中配置 parent:

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

模块打包的 pom 中配置 plugin:

<build>
   <plugins>
       <plugin>
           <groupId>com.alipay.sofa</groupId>
           <artifactId>sofa-ark-maven-plugin</artifactId>
           <!--           since ${sofa.ark.version} >= 2.2.13    -->
           <version>${sofa.ark.version}</version>
           <executions>
               <execution>
                   <id>default-cli</id>
                   <goals>
                       <goal>repackage</goal>
                   </goals>
               </execution>
           </executions>
           <configuration>
               <!-- 配置 “基座-dependencies-starter” 的标识,规范为:'${groupId}:${artifactId}':'version' -->
               <baseDependencyParentIdentity>com.alipay:${baseAppName}-dependencies-starter:0.0.1-SNAPSHOT</baseDependencyParentIdentity>
           </configuration>
       </plugin>
   </plugins>
</build>

步骤三 配置模块依赖白名单

对于部分依赖,即使模块和基座使用的依赖版本一致,但模块打包时也需要保留该依赖,即需要配置模块瘦身依赖白名单。

配置方式:在「模块项目根目录/conf/ark/bootstrap.properties」 或 「模块项目根目录/conf/ark/bootstrap.yml」中增加需要保留的依赖,如果该文件不存在,可自行新增目录和文件。以下提供了3个不同级别的配置,可根据实际情况进行添加。

# includes config ${groupId}:${artifactId}, split by ','
includes=org.apache.commons:commons-lang3,commons-beanutils:commons-beanutils
# includeGroupIds config ${groupId}, split by ','
includeGroupIds=org.springframework
# includeArtifactIds config ${artifactId}, split by ','
includeArtifactIds=sofa-ark-spi
# includes config ${groupId}:${artifactId}
includes:
  - org.apache.commons:commons-lang3
  - commons-beanutils:commons-beanutils
# includeGroupIds config ${groupId}
includeGroupIds:
  - org.springframework
# includeArtifactIds config ${artifactId}
includeArtifactIds:
  - sofa-ark-spi

步骤四 打包构建,并检查瘦身是否成功

执行 mvn clean package 打包构建出模块 ark-biz jar 包即可,您可以明显看出瘦身后的 ark-biz jar 包大小差异,也可以查看 ark-biz jar 包中 lib 文件夹中是否已经没有要排除的依赖了。

场景二:基座和模块协作松散,如多应用合并部署节省资源

在基座和模块协作松散的情况下,模块不应该在开发时感知基座正使用的依赖版本,因此模块更需要注重模块瘦身的低成本接入,可以配置模块打包需要排除的依赖。

方式一:SOFAArk 配置文件排包

步骤一

SOFAArk 模块瘦身会读取两处配置文件:

  • “模块项目根目录/conf/ark/bootstrap.properties”,比如:my-module/conf/ark/bootstrap.properties
  • “模块项目根目录/conf/ark/bootstrap.yml”,比如:my-module/conf/ark/bootstrap.yml

配置方式

bootstrap.properties (推荐)

在「模块项目根目录/conf/ark/bootstrap.properties」中按照如下格式配置需要下沉到基座的框架和中间件常用包,比如:

# 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
bootstrap.yml (推荐)

在「模块项目根目录/conf/ark/bootstrap.yml」中按照如下格式配置需要下沉到基座的框架和中间件常用包,比如:

# excludes 中配置 ${groupId}:{artifactId}:{version}, 不同依赖以 - 隔开
# excludeGroupIds 中配置 ${groupId}, 不同依赖以 - 隔开
# excludeArtifactIds 中配置 ${artifactId}, 不同依赖以 - 隔开
excludes:
  - org.apache.commons:commons-lang3
  - commons-beanutils:commons-beanutils
excludeGroupIds:
  - org.springframework
excludeArtifactIds:
  - sofa-ark-spi

步骤二

升级模块打包插件 sofa-ark-maven-plugin 版本 >= 2.2.12

    <!-- 插件1:打包插件为 sofa-ark biz 打包插件,打包成 ark biz jar -->
    <plugin>
        <groupId>com.alipay.sofa</groupId>
        <artifactId>sofa-ark-maven-plugin</artifactId>
        <version>${sofa.ark.version}</version>
        <executions>
            <execution>
                <id>default-cli</id>
                <goals>
                    <goal>repackage</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <skipArkExecutable>true</skipArkExecutable>
            <outputDirectory>./target</outputDirectory>
            <bizName>biz1</bizName>
            <webContextPath>biz1</webContextPath>
            <declaredMode>true</declaredMode>
        </configuration>
    </plugin>

步骤三

执行 mvn clean package 打包构建出模块 ark-biz jar 包即可,您可以明显看出瘦身后的 ark-biz jar 包大小差异,也可以查看 ark-biz jar 包中 lib 文件夹中是否已经没有要排除的依赖了。

您可点击此处查看完整模块瘦身样例工程。