SOFAArk 合并部署时,除了宿主应用,其他 Biz 允许运行时动态部署和卸载。Biz 的状态如下:

  • unresolved: 未注册,此时 Biz 包未被运行时解析
  • resolved: Biz 包解析完成,且已注册,此时 Biz 包还没有安装或者安装中
  • activated: Biz 包启动完成,且处于激活状态,可以对外提供服务
  • deactivated: Biz 包启动完成,但出于未激活状态,模块多个版本时,只有一个版本出于激活状态(注意这个状态只对 JVM 服务生效,对 RPC 等其他中间件无效)
  • broken: Biz 包启动失败后状态

目前 SOFAArk 提供了三种方式操作 Biz:

  • 编程 API
  • Zookeeper 动态配置
  • Telnet 指令

本质上,后两种都是通过编程 API 操作 Biz,所以在这里详细描述通过编程 API 控制 Biz 的生命周期。SOFAArk 提供客户端 ArkClient 操作 Biz, 主要包含三条指令:

  • install: 安装 Biz,虽然有多个重载方法,本质是接受 bizFile 文件作为入参
  • uninstall: 卸载 Biz,运行时 Biz 是由 bizName 和 bizVersion 唯一确定的,因此需要这两个入参
  • switch: 激活 Biz,SOFAArk 运行部署多个相同名称不同版本的 Biz,但是运行时只有一个 Biz 被激活(JVM 服务对外可用);当使用 switch 指令激活其他版本时,当前处于激活状态的 Biz 将切换到钝化,同样也需要 bizName 和 bizVersion 作为入参

注意:部署相同名称不同版本 Biz 时,如果已有激活的版本,后续部署的其他版本 Biz 将自动处于钝化状态

安装 Biz

以 Spring Boot/SOFABoot 为例,应用(模块)安装包含以下流程:

installation flow

  • 解析模块> SOFAArk 容器会解析文件流,读取 Biz 配置,创建 BizClassLoader 等,生成 Biz 运行时模型

  • 注册模块> 注册解析后的 Biz 模型,设置状态为 resolved

  • 启动模块> 执行 Biz 的入口方法,完成上下文的刷新,如果报错则对外抛出异常

  • 健康检查> 启动完成,此时 Biz 还没有切换至下一个状态,将会执行应用健康检查,健康检查参考 SOFABoot 文档,健康检查失败则抛出异常,如果应用没有引入 SOFABoot 健康检查依赖,则跳过

  • 切换状态> 健康检查成功,会切换 Biz 状态;如果不存在其他版本 Biz 处于激活状态,则切换状态至 Activated,否则切换状态至 DeActivated

注意:启动模块时抛出异常,均导致 Biz 启动失败,可以查看 sofa-ark/common-error.log 日志

卸载 Biz

应用(模块)卸载包含以下流程:

uninstallation-flow

  • 切换 Biz 状态至少 deactivated> 钝化 Biz, 防止流量进入正在卸载的 Biz

  • 关闭 ApplicationContext> 关闭 Biz 的 Spring 上下文,如果用户需要自定义卸载操作,可以监听 ContextClosedEvent 事件

  • 注销 JVM 服务> SOFAArk 运行时注销 Biz 发布的 JVM 服务

  • 发送卸载事件> 通知所有 Ark Plugin 和 Ark Biz,正在卸载某个 Biz

  • 清楚缓存> SOFAArk 运行时注销所有和该 Biz 相关的缓存

  • 切换 Biz 状态为 unresolved> Biz 执行完所有卸载操作时,将状态置为 unresolved

卸载面临的挑战

卸载 Biz 最大的挑战在于 ClassLoader 的卸载,如果 ClassLoader 没有卸载干净,极有可能会导致 metaspace OOM. JDK 对 Class 的回收条件非常苛刻,包含:

  • 该类所有实例都已经回收
  • 加载该类的 ClassLoader 已经回收
  • 该类对应的 java.lang.Class 对象已经没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

每个 Biz 都由独立的 BizClassLoader 加载,只要该 Biz 的加载的类或对象或 ClassLoader 被其他 Biz 或 Plugin 引用,则会导致 Biz 无法卸载成功

激活 Biz

激活指令用于设置 Biz 状态为 Activated,如果此时已有其他版本 Biz 处于激活状态,则先设置其为 Deactivated,再激活指定的 Biz 为 Activated. 激活状态是相对 JVM 服务而言,只有被激活的 Biz,其发布的 JVM 服务才能被其他 Biz 引用