阿里妹导读:FaaS—Function as a service,函数即服务。它是 2014 年由于亚马逊的 AWS Lambda 的兴起,而被大家广泛认知。FaaS 能力是 NBF 中的一项非常重要的能力,NBF 是一个非典型的 FaaS 架构,但是具备了典型的 FaaS 能力。文章将详细介绍 NBF 的 FaaS 容器架构、服务发布、服务路由和强大的 Serverless 能力以及 NBF-FaaS 在阿里大促期间的实践心得。
1.NBF
NBF (New-Retail Business Framework) 是供应链中台基础技术团队研发的新零售服务开放框架,提供了标准化业务定义、快捷服务开发和生态开放的能力,旨在为生态伙伴提供一整套完整的新零售 PaaS 和 SaaS 的解决方案。
2.FaaS
2.1 定义
FaaS 是 Serverless 的一种典型形式,由 Serverless 平台提供负载均衡、高可用、自动扩缩容、服务治理等最佳实践,将这些最佳实践对 Developer 透明化,进一步缩短 Developer 从想法到产品的时间,降低开发成本,同时保障 Developer 开发的服务的可靠性。通过事件驱动的方式,开发者的 Function 通过 Event 有效触发,比如 HTTP 请求、消息事件等。
2.2 典型架构
- Event Sources Function 事件驱动的集合;
- Function Instances 提供服务的 Function 或微服务;
- FaaS Controller 管理 Function 的控制服务,比如典型的 API Gateway 或者 BFF(Backend For Front)等;
- Platform Services Function 依赖的平台服务,如权限管理 API、对象存储服务等。
3.NBF-FaaS 架构
3.1 NBF-Platform Services
NBF 的平台能力主要分为三层:
(1)Serverless 平台—CSE(Cloud Service Engine):Serverless 是 FaaS 平台依赖的基础能力,这一块 NBF 与中间件 CSE 团队深度合作,CSE 提供快速的扩缩容的能力,可以在毫秒级别支持并行水平扩容和动态缩容,满足业务的错峰场景。基础技术团队与 CSE 共建容器冷热启动的性能优化以及 Serverless 运维工具 (日志,监控报警,链路跟踪等) 开发。
(2)NBF 容器:NBF 容器采用 OSGI 架构,提供了 Bundle 完整的生命周期管理,包括 Bundle 的加载,启动,卸载和注销等等,以及容器和 Bundle 的隔离和通信能力。
(3)平台能力:
- 服务发布:把 Function/Bundle 快速发布成服务的能力。
- 服务路由:服务多态,降级和 Mock 的路由能力。
- 服务管理:基于 SPI 和 Bundle 的版本管理和服务启停能力。
- 服务运维:服务的 Serverless 能力,混部能力,灰度能力和容灾降级能力等。
3.2 NBF-Function Instances
NBF 的函数实例对应的就是长在 NBF 服务市场的一个个服务背后的 Bundle 实现:
3.3 NBF-Event Sources
NBF 的 Event Sources 是由流程中心提供的基于 EventMap 的服务编排能力:
3.4 NBF-FaaS Controller
NBF 的 FaaS Controller 包括三种类型:
(1)流程中心调度服务 流程中心提供了调度 SPI 服务的事件驱动能力,包括流程事件,消息事件,定时事件等等,目前基本可以覆盖所有的事件驱动的业务场景。
(2)Broker 调用 RPC 服务 Broker 支持多模式调用 Bundle 发布的 RPC 服务,包括服务的多态路由,降级路由和 Mock 路由等。
(3)NBF-Rest 调用 HTTP 服务,NBF-Rest 支持调用 Bundle 发布的 HTTP 服务。
4. NBF 的 FaaS 能力
4.1 Bundle 生命周期管理——NBF 容器
- 4.1.1 NBF 容器架构
NBF 容器管理了 Bundle 的加载,启动,卸载和注销的完整周期,并采用 OSGI 机制实现了容器和 Bundle 之间的隔离和通信能力。
容器架构设计 :
NBF 容器架构主要分为三层:
(1)Serverless 层
这一层 NBF 和 CSE 团队共建,CSE 负责实现 Fast Auto-Scaling,目前已经在双十二和女王节等大促活动得到了充分验证。NBF 实现了 Fast Cold Start 和 Fast Hot Start Fast Cold Start—优化 Bundle 服务发布的冷启动时间 Fast Hot Start—优化 Bundle 服务 Scaling up 后的服务可用时间 底层依赖的 CaaS 服务目前也在跟随 CSE 的节奏从 Sigma3.0 向 ACK-EE 迁移,未来将全面支持阿里云单元。
(2)NBF-OSGI Framework
NBF-OSGI Framework 是采用 OSGI 机制实现了 Bundle 加载,启动,卸载和注销完整生命周期托管,目前在集团内部绝对多数都是 Pandora 应用,集团中间件都是通过 ModuleClassLoader 插件式加载,因此目前 NBF 容器的 Bundle 加载方式也是建立在 Pandora 的加载机制之上的 NBF-OSGI Framework 提供了一整套 Bundle 的隔离机制,Bundle 与容器的通信机制以及 Bundle 之间的通信机制。
-
- 容器与 Bundle 通信:容器提供了 import 机制,通过这种方式 Bundle 就可以使用容器能力,比如 Spring 的 context 托管,比如 AOP 能力
<imported>
<packages>
<package>org.springframework</package>
<package>org.apache.commons.logging</package>
<package>org.aopalliance</package>
<package>org.aspectj</package>
</packages>
</imported>
-
- Bundle 隔离:NBF 容器会为每个 Bundle 建立独立沙箱,从加载机制上保证了 Bundle 代码级别隔离,避免 Bundle 之间的类和资源冲突。
-
- Bundle 之间通信:NBF 容器持有 BundleContext 的全局管理器,支持 Bundle 把需要提供给其他 Bundle 使用的 Context 放到全局管理器中,从而实现了 Bundle 之间的通信。
(3)容器托管的 Bundle 和 Plugin
Bundle 无需多言,是业务方编写的业务逻辑代码 Plugin 是 NBF 引擎提供的增值能力,采用插件化的方式进行加载,比如 NBF-FaaS 能力中最核心的服务发布能力。
- 4.1.2 未来的 NBF 容器架构
前面提到了由于目前集团内部绝对多数都是 Pandora 应用,因此目前 NBF 的容器架构是建立 Pandora 的加载机制上的,本质上是 Run 在 Pandora 的容器内的。而未来的 NBF 容器架构是由 NBF-OSGI Framework 来托管外部容器,这些外部容器可以是 Pandora 容器,也可以是非 Pandora 容器,这样就实现了 NBF 容器对于 Pandora 容器的依赖倒置。而对于 Run 在 NBF-FaaS 平台的 Bundle 而言就具有更丰富的可变性。
NBF 新容器架构:
4.2 Bundle 服务发布
服务发布的核心原理如下图比较详细的介绍了 NBF 容器把 Bundle 发布成 RPC 服务的完整链路,核心主要包括三步:
- 依据路由表加载 Bundle;
- 通过 NBF Framework 加载和启动 Bundle;
- 通过 NBF Framework 加载和启动服务发布的 Plugin。
4.3 服务的路由和管控—Broker
- 4.3.1 Broker 架构:
Broker 架构主要分为:
Broker Agent
Broker Agent 实现了 Broker 的 SPI 和 Implement 的分离,通过 BrokerBundleLoader 动态加载 implement,这样 Broker 的版本升级对于使用方而言是不用做代码变更和重新发布。想想某些重型的二方库版本升级,每个业务方都需要深度感知,是不是觉得会舒爽很多。SPI Proxy 则实现了采用注解的方式来实现无侵入的服务调用,从传统的服务调用方式迁移到 NBF 的服务调用方式易如反掌。举个栗子:
(1)传统的服务调用方式:
@Autowired
ServiceA serviceA;serviceA.invoke(params);
(2)Broker SPI 调用方式:
@Autowired
BundleBroker bundleBroker;
bundleBroker.get(ServiceA.class).invoke(params);
(3)注解的调用方式:
@DynamicInject
ServiceA serviceA;
serviceA.invoke(params);
有了 @DynamicInject,是不是觉得 NBF 服务调用跟原有的传统调用方式没啥区别,对于 @DynamicInject 支持的几种方式。
Broker Bundle
对于 Broker Bundle 核心功能包括以下几块核心功能:
4.3.1.1 BundleProxy
BundleProxy 可以简单理解成是对 Bundle 运行的代理机制,比如 Bundle 的主动熔断和被动降级这些能力都是通过 BundleProxy 实现的,因为这些特性对于每个运行 Bundle 都是统一的机制。
4.3.1.2 服务发现
服务发现主要职责怎么找到需要调用的服务,怎么生成调用服务的 URI,拿 HSF 的服务寻址策略来对比,整个机制就简单了 HSF 的寻址 URI: Proxy://IP:port/service/version/method 对于 Broker 服务发现 IP 和 port 对应的容器本身的网络信息,这些可以通过 APPName 或者 Armory 分组以及未来 serverless 后的 GroupId 来获取 serviceName,version 这些数据就是第三层 Broker 数据层提供的 spi 和 bundle 元数据信息 有了这些基本信息以后,我们就可以生成 NBF 服务发现的 URI 了。
4.3.1.3 路由计算
在介绍路由计算之前,先介绍下先前提到 @DynamicInject 支持的几种方式:默认模式,规则模式和动态模式。
(1)默认模式:默认模式就是服务调用不需要指定任何路由参数,这种调用方式适合单 Bundle 实现的 SPI,Bundle 实现就是默认实现
@DynamicInject
private ConfigReadService configReadService;
ResultDO<List<ConfigDTO>> result = configReadService.queryConfig(new ConfigQuery);
(2)规则模式:规则模式支持三种方式指定路由参数:Id(业务身份),Expression(正则表达式),Rule(规则表达式)。
// 指定 bundleId 方式, type 默认为 ID
@DynamicInject(pattern = "drf")
// 指定正则方式
@DynamicInject(pattern = "^drf-hz.*$", type = "REG")
// 指定 Rule 方式
@DynamicInject(pattern = "{\"wareHouseId\":\"2001\"}", type = "RULE")
(3)动态模式:动态模式指的是编码时无法确定调用参数的场景,路由参数需要调用时传入。
@DynamicInject
private DynamicInvoker<ConfigReadService> configReadServiceDynamic;
ResultDO<List<ConfigDTO>> result;
// 动态传入 bundleId
result = configReadServiceDynamic.getService(bundleId).queryConfig(new ConfigQuery);
// 动态传入规则参数
Map<String, Object> params = new HashMap<>();
params.put("merchant", merchant);
result = configReadServiceDynamic.getService(params).queryConfig(new ConfigQuery);
路由计算又要再次提到我们先前提到过的 SpiProxy 了,SpiProxy 的职能主要有两个:
a. 获取 SPIInfo,包括 SPI 的 ClassName,SpiVersion 和 SpiCode 等等
b. 根据路由参数计算需要调用 BundleId 然后再根据我们在服务发现中提到的寻址策略,不难发现我们已经可以生成 NBF 服务调用的 URI,这就是 NBF 多态路由的核心原理。
4.1.3.4 熔断降级
熔断降级包括两个核心能力:被动降级和主动熔断。
(1)被动降级:被动降级会在三种情况下触发:服务找不到,服务返回异常和服务超时,这个时候服务调用会自动路由到 Bundle 对应的降级 Bundle。用个简单的表格解释下降级的含义:
(2)主动熔断:主动熔断是通过 NBF 设置基线指标来实现的,如果超过服务的基线指标,则路由到降级 Bundle。
在截图的栗子中我们选用 Bundle(供应链 - 批发服务 - 大润发实现)作为 Bundle(供应链 - 批发服务 - 盒马实现)的降级 Bundle,在超过基线指标 100ms 就会路由到降级 Bundle。对于熔断降级实现的核心原理就是我们先前提到过的 BundleProxy,这些特性对于每个运行 Bundle 都是统一的机制,通过 BundleProxy 识别是否满足主动熔断和被动降级的条件,然后再代理执行真正的 Bundle。
4.1.3.5 流量管控
流量管控提供了一种软负载的能力,支持设置 Bundle 和降级 Bundle 之间的流量配比,我们仍以 Bundle:供应链 - 批发服务 - 盒马实现为例,以图为证:
5. 服务的高可用运维
5.1 NBF-Serverless 能力
在先前提到的 NBF 容器架构中,NBF-Serverless 能力是 NBF 容器架构的重要基石,只有在 Serverless 实现毫秒级弹性扩缩容前提下,才能真正支撑错峰场景,才能最大程度的节约机器资源。
只有在 Serverless 实现服务资源统一弹性调度的前提下,才能真正实现 NBF 的服务部署隔离,而不是目前通过定制容器规格 (1Core2G,2Core4G,4Core8G 等等) 和 Bundle 混部的方式来实现 Bundle 部署隔离和机器资源之间的平衡。在这里一定要为 NBF 的深度合作伙伴——CSE 团队鼓个掌,他们已经具备了毫秒级 Auto-Scaling 能力,为我们提供了可靠的基础设施。
当然对于 Serverless 配套运维设施 (日志,监控报警,链路跟踪等) 和 Serverless 迁移到 ACK-EE 云单元这些事情,NBF 和 CSE 都还在路上。那在 NBF-Serverless 能力的建设过程中,NBF 又扮演什么角色呢?用一张图来简单表述下 Serverless 的实现原理以及 CSE 与 NBF 的职责划分。
- 5.1.1 Fast Auto-Scaling
Fast Auto-Scaling 是 CSE 提供的核心基础设施能力,毫秒级的弹性扩容主要包括几个步骤:
(1)种子机器的启动 种子机器的启动就是冷启动的过程,这个过程跟当前集团 APP 启动的方式无异,就是容器启动,镜像加载和服务暴露的几个步骤,因此冷启动的时间普遍来说是分钟级别的。
(2)种子分发 通过 Fork2 的技术实现了种子机器的内存复制,而把内存复制到扩容机器上的时间是极短的,因此 CSE 的 Auto-Scaling 可以毫秒级实现并行水平扩容。
(3)服务注册 这个过程实际上就是在 ConfigServer 完成服务注册,从而可以保障复制出来的 Service Bean 是可被调用的。
- 5.1.2 Fast Cold Start
NBF 在 NBF-Serverless 能力构建中第一个重要事项就是实现冷启动优化,我们期望把冷启动的启动从分钟级别优化到秒级,因此调整了 NBF Bundle 的冷启动机制:
(1)在 Bundle 创建机器分组和扩容分组的时候提前部署 Engine。
(2)通过 NBF 的 FaaS 能力动态加载 Bundle,原来,冷启动时间 =Pandora 容器的启动时间 +Engine 的启动时间 +Bundle 的 install 和 start 时间,经过优化以后,冷启动时间 =Bundle 的 install 和 start 时间。
- 5.1.3 Fast Hot Start
由于当前的扩容机制是通过内存复制实现的,而类似于 UUID 这种与机器有关的内存变量的复制是不合适的,因此 NBF 的热启动优化主要是提供了 refresh 内存变量的机制。NBF 的 Framework 托管了 Bundle 生命周期管理,也提供相应的 Hook 能力,通过这些 Hook 就能解决 UUID 这种问题。
- 5.1.4 Serverless 实践
虽然目前 Serverless 运维配套能力还不够完善,但是我们仍然在去年双十二和今年女王节上线了几个 P0 级服务,验证在大促场景下 Serverless 的稳定性和毫秒级的 Auto-Scaling 能力。当然我们敢在 S 级的大促中验证 P0 级服务也是有所依仗的,那就是 NBF 的熔断降级和流量管控能力。
文描服务在女王节当天的 QPS 流量从 4000+ 飙升到 12 万,Serverless 非常迅速的扩容到 10 台,妥妥的支撑了业务峰值。而对于机器资源的节约就显而易见了,原来文描服务根据业务体量常态部署的 10 台,而 Serverless 目前只需要常态部署 2 台(其实可以只部署 1 台,2 台可以认为是容灾),而终态 Serverless 将解决长尾服务的问题,最终可以缩容到 0 台,这样对机器资源是更大程度的节约。
下图是女王节期间的 Serverless 前后的指标体系对比:
从图中的数据可以看出,整个文描服务在大促期间表现出来的系统稳定性和服务稳定性是完全可靠的,这也就充分验证 NBF-Serverless 的可行性。
5.2 极速回滚
极速回滚是 NBF 服务高可用运维一种非常有效的手段。传统的 APP 回滚方式是重新编译、构建、打包和部署,而 NBF 具备典型的 FaaS 能力,对于 Bundle 回滚只需要重新 load 指定回滚版本的 Jar 包而已,而 NBF Engine 又是常驻容器,因此 Bundle 回滚速度是非常之快的。
6. 总结
文章比较详细的介绍了 NBF 的 FaaS 能力,一句话总结:NBF 是非典型的 FaaS 架构,但是具备典型的 FaaS 能力。
开篇介绍了业界对于 FaaS 的广泛定义,然后对比了 FaaS 典型架构和 NBF-FaaS 的非典型架构之间的关系,之后重点介绍 NBF 的 FaaS 能力,包括 NBF 的容器架构,Bundle 的服务发布和 Bundle 路由与管控的核心实现原理。最后表述了 NBF 的高可用运维能力,重点表述了 NBF-Serverless 的实现原理和具体实践心得。现在 NBF 从生长的盒马回归到供应链中台,为包括盒马在内的 25 个 BU 和合作伙伴提供生态开放能力。
本文作者:冯微峰(诸葛瑾)
阅读原文
本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。