蚂蚁金服 SOFAArk 0.6.0 新特性介绍 | 模块化开发容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 蚂蚁金服在 SOFAStack 体系内研发了一款基于 Java 实现的轻量级类隔离容器,主要提供类隔离和应用(模块)合并部署能力--SOFAArk。本篇文章为 SOFAArk 0.6.0 的新特性介绍。

SOFAStack
Scalable  Open Financial Architecture Stack 是蚂蚁金服自主研发的金融级分布式架构,包含了构建金融级云原生架构所需的各个组件,是在金融场景里锤炼出来的最佳实践。

蚂蚁金服在 SOFAStack 体系内研发了一款基于 Java 实现的轻量级类隔离容器,主要提供类隔离和应用(模块)合并部署能力--SOFAArk。本篇文章为 SOFAArk 0.6.0 的新特性介绍。
GitHub 地址:https://github.com/alipay/sofa-ark

简介

在大型软件开发过程中,通常会推荐底层功能插件化、业务功能模块化的开发模式,以其达到低耦合、高内聚、功能复用的优点。基于此,SOFAArk 提供了一套较为规范化的插件化、模块化开发方案,产品能力主要包括:

  • 定义插件开发规范,提供 Maven 打包工具,简单快速将多个二方包打包成插件(Ark Plugin,以下简称 Plugin), 适用于将底层组件插件化输出,例如 RPC、富客户端等;
  • 定义模块开发规范,提供 Maven 打包工具,简单快速将应用(Spring Boot/SOFABoot/普通 Java 应用)打包成模块 (Ark Biz,以下简称 Biz),适用于将业务组件模块化输出,提升业务能力复用;
  • 定义类加载模型,运行时 Plugin、Biz 之间均相互隔离,运行时由不同的 ClassLoader 加载,有效避免相互之间的包冲突,降低 Plugin 和 Biz 对运行环境的要求;
  • 定义标准的编程界面,包括服务、事件、扩展点等机制,方便 Plugin、Biz 交互和扩展;
  • 定义业务模块 (Biz) 生命周期,支持多 Biz 合并部署。开发阶段将多个 Biz 打包成 Executable Ark Jar 包(以下简称 Ark 包),或者运行时使用 API 或配置中心(Zookeeper)动态地管理 Biz 安装和卸载,满足多应用合并部署及动态升级的需求。

基于以上能力,SOFAArk 可以帮助解决多应用(模块)合并部署、动态升级、依赖包冲突等场景问题。

场景

场景一:合并部署

复杂项目通常需要跨团队协作开发,各自负责不同的组件。协调跨团队合作开发会遇到不少问题:比如各自技术栈不统一导致的依赖冲突、往同一个 Git 仓库提交代码常常导致 merge 冲突、组件功能相互依赖影响测试进度。因此,如果能让每个团队将负责的功能组件当成一个个单独的应用开发和测试,运行时合并部署,那么将有助于提升开发效率及应用可扩展性。

SOFAArk 提出了一种特殊的包结构 -- Ark Biz,用户可以使用 Maven 插件将应用打包成 Biz,允许多 Biz 在 SOFAArk 容器之上合并部署,并通过统一的编程界面交互,如下:

Biz 对应用类型没有限制,可以是 Spring Boot/SOFABoot/Java 普通应用类型,Biz 之间采用统一的编程界面-SOFA JVM服务进行交互。发布和引用服务也非常简单,使用 API 或者 Spring 注解/XML 方式:

合并部署的形式,分为两种 -- 静态合并部署和动态合并部署。

静态合并部署

在开发阶段,应用可以将其他应用打成的 Biz 包通过 Maven 依赖的方式引入,而当自身被打成 Ark 包时,会将引入的其他 Biz 包一并打入。通过 java -jar 启动 Ark 包时,则会根据优先级依次启动各 Biz,单个 Biz 使用独立的 BizClassLoader 加载,不需要考虑依赖包冲突问题,Biz 之间则通过 SOFA JVM 服务交互。

动态合并部署

动态合并部署区别于静态合并部署最大的一点是,在运行时可以通过 API 或者配置中心(Zookeeper)来控制 Biz 的部署和卸载。动态合并部署的设计理念图如下:

无论是静态抑或动态合并部署都有存在宿主应用 (master biz) 的概念,如果 Ark 包只打包了一个 Biz,则该 Biz 默认成为宿主应用;如果 Ark 包打包了多个 Biz 包,需要配置指定宿主应用。宿主 Biz 和其他 Biz 唯一不同在于,宿主 Biz 不允许被卸载。

一般而言,宿主应用会作为流量入口的中台系统,具体的服务实现会放在不同的动态 Biz 中,供宿主应用调用。宿主应用可以使用 SOFAArk 提供的客户端 API 实现动态应用的部署和卸载。除了 API, SOFAArk 提供了 Config Plugin,用于对接配置中心(目前支持 Zookeeper),运行时接受动态配置;Config Plugin 会解析下发的配置,控制动态应用的部署和卸载。

场景二:动态升级

SOFAArk 在蚂蚁内部也被用来解决动态升级的场景问题。有时候,因为业务迭代较快,应用依赖的某二方包需要频繁的变更,这将导致应用每次都因为升级二方包版本做变更发布,影响开发效率;而作为二方包的开发者,常常因为推动依赖方应用升级阻力较大,导致新特性无法按时上线,影响业务发展。

为了加快创新业务的迭代速度,会将需要频繁变更的二方包打包成 Biz 包,供其他应用依赖。作为依赖方,不会直接在 Pom 文件(假设是使用 Maven 构建)定义 Biz 包版本,而是通过配置中心(例如 Zookeeper)下发配置。如此,当应用启动时,会拉取 Biz 版本配置信息,进而拉取正确版本的 Biz 包并启动。如此,当需要依赖方升级 Biz 版本时,只需要在配置中心重新推送配置即可。

场景三:依赖隔离

日常使用 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 包的这两个版本无法兼容:

此时,即可使用 SOFAArk 解决该依赖冲突问题:只需要把 A 和版本为 0.1 的 C 包一起打包成一个 Ark 插件,然后让应用工程引入该插件依赖即可。

不仅仅是在出现依赖包冲突时,可以通过打包 Ark Plugin 解决,对于复杂的底层组件,例如 RPC 组件,为了防止它和依赖方应用存在包冲突,常会将 RPC 或其他中间件组件单独打成 Plugin 输出。

其次,Ark Plugin 也被用于扩展 SOFAArk 容器能力,例如 runtime-sofa-boot-plugin 用于提供 SOFA JVM 服务通信能力; web-ark-plugin 用于提供多 web 应用合并部署能力等。

原理

在介绍完 SOFAArk 的使用场景之后,我们简单介绍其类加载模型。SOFAArk 包含三个概念,Ark Container, Ark Plugin 和 Ark Biz; 运行时逻辑结构图如下:

在介绍这三个概念之前,先介绍 Executable Ark Jar 包概念:Ark 包是 SOFAArk 定义的特殊格式的可执行 Jar 包。SOFAArk 提供的 Maven 插件 sofa-ark-maven-plugin 可以将单个或多个 Biz打包成 Ark 包,使用 java -jar命令即可在 SOFAArk 容器之上启动所有应用。Ark 包通常包含 Ark Container、Ark Plugin 和 Ark Biz。下面是一个简单的 Ark 包工程目录:

可以很直观的看到 Ark Container、Ark Plugin 和 Ark Biz 在 Ark 包的组织形式中。针对这三个概念我们简单做下名词解释:

  • Ark Container: SOFAArk 容器,负责 Ark 包启动运行时的管理。Plugin 和 Biz 运行在 SOFAArk 容器之上,容器具备管理插件和应用的功能,容器启动成功后会自动解析 classpath 包含的 Plugin 和 Biz 依赖,完成隔离加载并按优先级依次启动。
  • Ark Plugin: SOFAArk 定义的特定目录格式的 Fat Jar,使用 Maven 插件 sofa-ark-plugin-maven-plugin 可以将多个二方包打包成一个 Plugin 对外插件化输出。Plugin 会包含一份配置文件,通常包括插件类导入导出配置、资源导入导出配置、插件启动优先级等;运行时,SOFAArk 容器会使用独立的 PluginClassLoader 加载插件,并根据插件配置构建类加载索引表、资源加载索引表。插件和插件之间、插件和应用之间相互隔离。
  • Ark Biz: SOFAArk 定义的特定目录格式的 Fat Jar,使用 Maven 插件 sofa-ark-maven-plugin 可以将应用打包成 Biz 包。Biz 是工程应用以及其依赖包的组织单元,包含应用启动所需的所有依赖和配置。一个 Ark 包中可以包含多个 Biz 包,按优先级依次启动,Biz 之间通过 SOFA JVM 服务 交互。

启动 Ark 包,Ark Container 优先启动,容器运行时自动解析 Ark 包中包含 Plugin 和 Biz,并读取他们的配置信息,构建类和资源的加载索引表;然后使用独立的 ClassLoader 加载并按优先级配置依次启动。需要指出的是,Plugin 优先 Biz 被加载启动。

SOFAArk 内部的类加载模型相对比较简单,Plugin 之间是双向类索引关系,即可以相互委托对方加载所需的类和资源;Plugin 和 Biz 是单向类索引关系,即只允许 Biz 索引 Plugin 加载的类和资源,反之则不允许。

总结

SOFAArk 定义了一套相对简单的类加载模型,并结合特殊的打包格式、统一的编程界面、易扩展的插件机制,从而提供了一套较为规范化的插件化、模块化的开发方案。更多内容可以参考官方文档

文中涉及的相关链接

与 SOFA 相遇

3 月 24 日(本周日下午),SOFA Meetup#1-服务注册中心、分布式事务重磅发布 将在北京举行。
席位有限,点击链接即可报名:https://tech.antfin.com/activities/382
倒计时 3 天!期待与大家见面~

主海报-终.jpg

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
3月前
|
Java 持续交付 Docker
微服务框架(二十一)Piplin 持续部署 Docker 容器
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文为使用Piplin 持续部署 Docker 容器
|
4月前
|
Kubernetes 持续交付 开发者
开源容器的魅力:探索使用开源容器的奥秘
随着云计算和微服务架构的蓬勃发展,开源容器技术如Docker和Kubernetes等正在改变应用程序的构建、交付和管理方式,开源容器技术成为了构建、交付和管理应用程序的重要工具。作为开发者,关于开源容器的使用也是在逐渐变多,那么本文就来分享一下开发者关于使用开源容器的原因,以及一些使用开源容器的经验,本文只做简单的分享,且只代表个人观点,如有不同意见欢迎评论区交流。
44 1
开源容器的魅力:探索使用开源容器的奥秘
|
3月前
|
运维 监控 安全
深入探究 Rancher 容器编排平台的核心概念与实践
Rancher 是一款开源的容器编排平台,它可以帮助开发人员和 IT 运维团队更加高效地管理容器化应用程序。本文将深入探究 Rancher 的核心概念和实践,包括其架构、功能和部署流程等方面的内容。
|
5月前
|
Kubernetes Linux 微服务
微服务轮子项目(42) -容器管理平台
微服务轮子项目(42) -容器管理平台
106 0
|
7月前
|
负载均衡 算法 Java
SpringCloud原生五大组件简述
SpringCloud原生五大组件简述
1096 0
|
关系型数据库 MySQL Java
12-微服务技术栈(高级):容器引擎Docker
在前面的学习中,我们掌握了微服务的服务注册与发现(nacos)、配置中心(nacos)、远程服务调用(feign)、网关(gateway),同时借助Idea编译工具多次完成本地服务启动、部署和验证。在微服务架构中,不会再像传统那样单个单个部署服务器,而是会借助Docker进行批量的容器化部署。
429 0
微搭低代码数据容器组件使用解析
微搭低代码数据容器组件使用解析
微搭低代码数据容器组件使用解析
|
JavaScript 前端开发 Cloud Native
阿里巴巴 Noslate 正式开源 - 面向云原生的 JavaScript 容器方案
继 2019 年开源 Midway 框架之后,阿里一直在 Node.js 的前沿进行深度研究,除了加入 TC39 参与标准化建设,向上游 Node.js 项目持续贡献,与龙蜥社区合作优化之外,也在 Serverless 领域有了不小的成果。
980 0
阿里巴巴 Noslate 正式开源 - 面向云原生的 JavaScript 容器方案
|
存储 Kubernetes Cloud Native
【云原生 | 从零开始学Kubernetes】十二、k8spod的生命周期与容器钩子
Pod 里面可以有一个或者多个容器,部署应用的容器可以称为主容器,在创建 Pod 时候,Pod 中 可以有一个或多个先于主容器启动的Init 容器,这个 init 容器就可以成为初始化容器,初始化容器一旦执行完,它从启动开始到初始化代码执行完就退出了,它不会一直存在,所以在主容器启动之前执行初始化,初始化容器可以有多个,多个初始化容器是要串行执行的,先执行初始化容器 1,在执行初始化容器 2等,等初始化容器执行完初始化就退出了,然后再执行主容器,主容器一退出,pod 就结束了,主容器退出的时间点就是 pod 的结束点,它俩时间轴是一致的
298 0
【云原生 | 从零开始学Kubernetes】十二、k8spod的生命周期与容器钩子
|
数据采集 运维 Kubernetes
如何基于 OpenKruise 打破原生 Kubernetes 中的容器运行时操作局限?
本文分享了 OpenKruise 中一些功能的用法,以及它如何与 Kubelet 和 CRI 合作。如何基于 OpenKruise 打破原生 Kubernetes 中的容器运行时操作局限。
如何基于 OpenKruise 打破原生 Kubernetes 中的容器运行时操作局限?