SOFAArk 是一款基于 Java 实现的轻量级类隔离容器,主要提供类隔离和应用(模块)合并部署能力,由蚂蚁金服公司开源贡献;
在大型软件开发过程中,通常会推荐底层功能插件化,业务功能模块化的开发模式,以期达到低耦合、高内聚、功能复用的优点。基于此,SOFAArk 提供了一套较为规范化的插件化、模块化的开发方案,产品能力主要包括:
- 定义类加载模型,运行时底层插件、业务应用(模块)之间均相互隔离,单一插件和应用(模块)由不同的 ClassLoader 加载,可以有效避免相互之间的包冲突,提升插件和模块功能复用能力;
- 定义插件开发规范,提供 maven 打包工具,简单快速将多个二方包打包成插件(Ark Plugin,以下简称 Plugin)
- 定义模块开发规范,提供 maven 打包工具,简单快速将应用打包成模块 (Ark Biz,以下简称 Biz)
- 针对 Plugin、Biz 提供标准的编程界面,包括服务、事件、扩展点等机制
- 支持多 Biz 的合并部署,开发阶段将多个 Biz 打包成可执行 Fat Jar,或者运行时使用 API 或配置中心(Zookeeper)动态地安装卸载 Biz
基于以上能力,SOFAArk 可以帮助解决依赖包冲突、多应用(模块)合并部署等场景问题。
官网 :https://www.sofastack.tech/projects/sofa-boot/sofa-ark-readme/
GitHub 地址: https://github.com/sofastack/sofa-ark
https://juejin.cn/post/6844903653828984845
和 OSGi 对比
作为开源界早负盛名的动态模块系统,基于 OSGi 规范的 Equinox、Felix 等同样具备类隔离能力,然而他们更多强调的是一种编程模型,面向模块化开发,有一整套模块生命周期的管理,定义模块通信机制以及复杂的类加载模型。作为专注于解决依赖冲突的隔离框架,SOFAArk 专注于类隔离,简化了类加载模型,因此显得更加轻量。
其次在 OSGi 规范中,所有的模块定义成 Bundle 形式,作为应用开发者,他需要了解 OSGi 背后的工作原理,对开发者要求比较高。在 SOFAArk 中,定义了两层模块类型,Ark Plugin 和 Ark Biz,应用开发者只需要添加隔离的 Ark Plugin 依赖,对本身的开发没有任何影响,基本没有开发门槛。
为了彻底解决包冲突的问题,需要借助类隔离机制,使用不同的 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 包的这两个版本无法兼容:
合并部署
复杂项目通常需要跨团队协作开发,各自负责不同的组件,而众所周知,协调跨团队合作开发会遇到不少问题;比如各自技术栈不统一导致的依赖冲突,又比如往同一个 Git 仓库提交代码常常导致 merge 冲突。因此,如果能让每个团队将负责的功能组件当成一个个单独的应用开发,运行时合并部署,通过统一的编程界面交互,那么将极大的提升开发效率及应用可扩展性。SOFAArk 提出了一种特殊的包结构 – Ark Biz,用户可以使用 Maven 插件将应用打包成 Biz,允许多 Biz 在 SOFAArk 容器之上合并部署,并通过统一的编程界面交互。
静态合并部署
SOFAArk 提供了静态合并部署能力,在开发阶段,应用可以将其他应用打成的 Biz 包通过 Maven 依赖的方式引入,而当自身被打成可执行 Fat Jar 时,可以将其他应用 Biz 包一并打入,启动时,则会根据优先级依次启动各应用。每个 Biz 使用独立的 BizClassLoader 加载,不需要考虑相互依赖冲突问题,Biz 之间则通过 SofaService/SofaReference JVM 服务进行交互。
动态合并部署
动态合并部署区别于静态合并部署最大的一点是,运行时通过 API 或者配置中心(Zookeeper)来控制 Biz 的部署和卸载。动态合并部署的设计理念图如下:
无论是静态还是动态合并部署都会有宿主应用(master biz)的概念, 如果 Ark 包只打包了一个 Biz,则该 Biz 默认成为宿主应用;如果 Ark 包打包了多个 Biz 包,需要配置指定宿主应用。宿主应用不允许被卸载,一般而言,宿主应用会作为流量入口的中台系统,具体的服务实现会放在不同的动态 Biz 中,供宿主应用调用。宿主应用可以使用 SOFAArk 提供的客户端 API 实现动态应用的部署和卸载。除了 API, SOFAArk 提供了 Config Plugin,用于对接配置中心(目前支持 Zookeeper),运行时接受动态配置;Config Plugin 会解析下发的配置,控制动态应用的部署和卸载。
原理
SOFAArk 包含三个概念,Ark Container, Ark Plugin 和 Ark Biz; 运行时逻辑结构图如下:
Ark 包是满足特定目录格式要求的可运行 Fat Jar,使用官方提供的 Maven 插件 sofa-ark-maven-plugin 可以将单个或多个应用打包成标准格式的 Ark 包;使用 java -jar 命令即可在 SOFAArk 容器之上启动所有应用;Ark 包通常包含 Ark Container、Ark Plugin 和 Ark Biz;以下我们针对这三个概念简单做下名词解释:
- Ark Container: SOFAArk 容器,负责 Ark 包启动运行时的管理;Ark Plugin 和 Ark Biz 运行在 SOFAArk 容器之上;容器具备管理插件和应用的功能;容器启动成功后,会自动解析 classpath 包含的 Ark Plugin 和 Ark Biz 依赖,完成隔离加载并按优先级依次启动之;
- Ark Plugin: Ark 插件,满足特定目录格式要求的 Fat Jar,使用官方提供的 Maven 插件 sofa-ark-plugin-maven-plugin 可以将一个或多个普通的 Java jar 打包成一个标准格式的 Ark Plugin;Ark Plugin 会包含一份配置文件,通常包括插件类导入导出配置、资源导入导出配置、插件启动优先级等;运行时,SOFAArk 容器会使用独立的 PluginClassLoader加载插件,并根据插件配置构建类加载索引表、资源加载索引表,使插件和插件之间、插件和应用之间相互隔离;
- Ark Biz: Ark 应用模块,满足特定目录格式要求的 Fat Jar,使用官方提供的 Maven 插件 sofa-ark-maven-plugin 可以将工程应用打包成一个标准格式的 Ark Biz;Ark Biz 是工程应用以及其依赖包的组织单元,包含应用启动所需的所有依赖和配置;一个 Ark 包中可以包含多个 Ark Biz 包,按优先级依次启动,Biz 之间通过 JVM 服务交互;
运行 Ark 包,Ark Container 优先启动,容器自动解析 Ark 包中含有的 Ark Plugin 和 Ark Biz,并读取他们的配置信息,构建类和资源的加载索引表;然后使用独立的 ClassLoader 加载并按优先级配置依次启动;需要指出的是,Ark Plugin 优先 Ark Biz 被加载启动;Ark Plugin 之间是双向类索引关系,即可以相互委托对方加载所需的类和资源;Ark Plugin 和 Ark Biz 是单向类索引关系,即只允许 Ark Biz 索引 Ark Plugin 加载的类和资源,反之则不允许
Ark 包
SOFAArk 定义特殊格式的可执行 Jar 包,使用官方提供的 Maven 插件 sofa-ark-maven-plugin 可以将工程应用打包成一个标准格式的 Ark 包;使用命令 java -jar 即可在 SOFAArk 容器之上启动应用;Ark 包 通常包含 Ark Container 、Ark Plugin 依赖(如果有)、合并部署的 Ark Biz (如果有)以及应用自身的 Ark Biz;详情可参考 Ark 包;
Ark Container
Ark 容器,Ark Plugin 和 Ark Biz 运行在 SOFAArk 容器之上;容器具备管理多插件、多应用的功能;容器启动成功后,会解析 Ark Plugin 和 Ark Biz 配置,完成隔离加载并按优先级依次启动之;Ark Container 一般不会被用户直接感知,由打包插件 sofa-ark-maven-plugin 自动打入。详情可参考 SOFAArk 容器启动;
Ark Plugin
Ark 插件,SOFAArk 定义特殊格式的 Fat Jar,使用官方提供的 Maven 插件 sofa-ark-plugin-maven-plugin 可以将一个或多个普通的 Java Jar 包打包成一个标准格式的 Ark Plugin; Ark Plugin 会包含一份配置文件,通常包括插件类和资源的导入导出配置、插件启动优先级等;运行时,Ark 容器会使用独立的 PluginClassLoader 加载插件,并根据插件配置构建类加载索引表,从而使插件与插件、插件与应用之间相互隔离;详情可参考 Ark Plugin;
Ark Biz
Ark 模块,SOFAArk 定义特殊格式的 Fat Jar ,使用官方提供的 Maven 插件 sofa-ark-maven-plugin 可以将工程应用打包成一个标准格式的 Ark Biz 包;作用有二点,一、在 Ark 包 中,作为工程应用模块及其依赖包的组织单元;二、可以被其他应用当成普通 Jar 包依赖,用于在同一个 SOFAArk 容器启动多个 Ark Biz;多个 Ark Biz 共享 Ark Container 和 Ark Plugin ;详情可参考 Ark Biz;
合并部署
SOFAArk 允许将多个应用(Biz 包)合并打入到 Ark 包中,当启动 Ark 包时,会启动所有应用;也支持在运行时通过 API 或者配置中心(例如 Zookeeper)动态的部署和卸载应用,这些应用同时运行在同一个 JVM 中,由独立的 BizClassLoader 加载,各应用之间通过 SofaService/SofaReference 实现交互,称之为多应用的合并部署。
宿主应用
宿主应用是相对合并部署而言,在打包 Ark 包时,至少有一个 Biz 包被打入,如果应用引入了其他 Biz 包,则 Ark 包中会存在多个 Biz 包。当只有一个 Biz 包时,默认将其设置为宿主应用;如果存在多个 Biz 包,则需要配置指定宿主应用。宿主应用相对其他 Biz 包最大的不同,即不允许被卸载。
简单总结下,在 SOFAArk 框架中,应用(配置、源码、依赖)被打包成 Biz 包组织在一起,但是特殊的依赖(Ark Plugin 和其他应用 Biz 包)不会被打入 Biz 包中,Biz 包是不可执行的 Fat Jar; Ark Plugin 是特殊的二方包,可以将多个二方依赖打包成 Plugin,运行时由独立的 PluginClassLoader 加载,根据打包时配置的导出导入资源、类,构建运行时类加载模型;Ark 包是可执行 Fat Jar,一般由 Ark Container、Ark Plugin(0个或多个)、Ark Biz(至少一个)。