基于Nomad的FaaS函数运行时设计与实现(4)

453 阅读7分钟

4.3.3 函数预热

基于Nomad的边缘计算平台需要考虑到降低能耗,扩缩容策略,默认是支持缩容到零的。有时应对特殊的业务场景,需要冷启动优化,降低平均响应时延,提升服务体验质量。基于本文的平台冷启动优化考虑可以有两种方式:

l 函数预热。在真正业务请求到来时,确保有提供服务的函数实例。

l 通过/async/function/function_ name路由使用异步调用。

函数预热的实现,可以硬标准和软标准两种策略,本文采用软标准的策略实现。

l 硬标准是在配置时,就将其设置为不要将函数的规模缩小到0,保证最小可用性,即1/1个副本,需要在作业配置层面指定,此处不再赘述。

l 软标准是以最开始的一部分函数调用请求来预热函数,具体地讲是函数副本数从0扩容到1(或指定的函数最少副本数)的过程。函数预热的过程相对正常调用有较长的时延,这里定义为冷启动时间。

本文在FaaS API网关中增加实现函数预热功能。时序图如图4.10所示。

1. FunctionScaler的职责是进行函数扩容,返回函数扩容结果供业务调用,在内部逻辑过程中设置函数副本数。

2. 接收业务请求后,进行函数预热,查询函数缓存,如果存在函数元数据则返回扩容结果。

3. 如果不存在则直接通过ServiceQuery查询函数服务。

4. 实现ServiceQuery接口与FaaS API网关交互查询或设置函数副本数。函数预热就在此处将函数副本数设置为指定的函数最少副本数。

5. 实际函数镜像的启动和调度层面还是落实到平台层,由FaaS-Nomad-Provider调用Nomad API处理。

6. 返回结果,当函数预热后,将函数加入函数缓存。

image.png

图4.10  函数预热实现时序图

如表4.2所示,提供以下配置参数进行细节控制。

表4.2  函数预热与伸缩相关配置参数

参数说明默认值
scale_from_zero网关是否将服务从0个副本扩展到其配置的最小副本数false
faas.scale.max函数配置伸缩的最大副本数20
faas.scale.min函数配置最少的副本数1
faas.scale.factor伸缩的因子,max*factor/100取整20
faas.scale.poll.maxcount轮询函数服务查询的最大次数1000
faas.sacle.poll.interval轮询函数Readiness状态的间隔50ms
faas.sacle.cache.expiry函数缓存失效的时长5s
faas.sacle.retries函数伸缩的最大错误重试次数20

预热时容器拉起需要时间,尤其从0到1没有函数实例处理业务请求,冷启动时长会很明显。后期也可以考虑实现FunctionScaler对指定的函数定时请求一趟的函数预热策略,尽量确保在真实的业务请求前已有服役的函数实例。

4.3.4 函数工作流程

函数工作流程(Workflow)是起到函数层面的编排的作用,类似AWS Step Functions的功能。CNCF Serverless工作组正在制定workflow标准,但仍在Draft阶段。在此之前,本文尝试基于OpenFaaS实现了一套工作流系统,可以在OpenFaaS的stack.yml中定义函数间组合等关系。

函数工作流程的设计,遵循了以下目标:

l 利用OpenFaaS平台

l 不违反函数的概念

l 提供灵活性、可伸缩性和适应性

所以本文将函数工作流程设计为:一个函数faas-workflow,就和其他函数一样。函数工作流程允许用户只编写专注于解决一个问题的函数,而不必担心下一个问题。函数工作流程编排使函数与业务逻辑松散耦合,从而促进函数的可重用性。编写的无状态函数能够在多个应用程序之间使用,由函数工作流程为每个请求维护单个工作流程的执行状态。

faas-workflow函数的设计采用适配器模式保证无代码侵入性。如图4.11所示,其中,适配器(Adapter)是流程,被适配的对象(Adaptee)是函数。每个节点的执行是由faas-workflow处理对函数的调用,执行结束后,再将事件转发回来。通过这种方式,函数编排逻辑与功能相分离,并在适配器中实现。Adapter与Adaptee是组合关系,组合不需要侵入修改已有代码,使得函数完全独立于组合的细节。

image.png

图4.11  函数工作流程中适配器模式示意图

以上一个流程节点对应一个函数,实际上可以使用聚合模式将多个函数纳入一个流程节点,这个流程节点中以函数链的方式维护了多个函数的调用次序,如图4.12所示。通过这种方式,可以将一个执行节点实现为一个聚集器函数,该函数调用多个函数来收集结果,可选地应用业务逻辑,并将整合后的响应返回给客户端或转发给下一个节点。faas-workflow融合了适配器模式和聚合模式,可以支持更复杂的用例。

image.png

图4.12  函数工作流程中聚合模式示意图

实现上,将工作流程用有向无环图(Directed Acyclic Graph,DAG)表示,将任务分解的环节抽象为节点,将节点与节点的连接关系抽象为边。DAG支持并行分叉,这也符合函数工作流程中的并行分支的情况,但分支可能带有动态的条件(Condition)。将DAG中节点处的操作(Operation)分为三类:执行函数调用、执行HTTP请求回调、响应结果修改加工。有向边表示数据流向(Forward)或分支(Branch),如果节点的入度大于1,节点处需要聚合器(Aggregator)将多个输入聚合成一个。

当执行出现分支时,一个节点依赖于多个前任节点。当执行出现分支时,一个节点依赖于多个前任节点。分布式系统协调是通过集中式服务实现的,协调控制逻辑中需要抽象StateStore接口来使用任何外部同步KV存储库。实现中使用Consul做状态存储。

另外,函数执行的结果和中间数据可以由用户手动处理,需要为中间结果提供数据存储操作:初始化、存储、检索和删除节点之间的数据。这非常适合边缘计算流式数据处理场景下的应用程序。需要抽象DataStore接口可以使用任何外部对象存储。实现中使用MinIO做高性能对象存储。

节点的执行由一个或多个先前节点的完成事件驱动,将完成事件定义为之前所有的独立节点都已执行完成。事件携带执行状态并标识下一个要执行的节点,通过迭代直到所有流程节点都被执行。faas-workflow基于的OpenFaaS平台使用NATS进行事件交付的异步处理。

如图4.13所示,本文将函数工作流程的编排简单归类为下面四类模型的组合:同步链结构、异步链结构、带分支的并行结构和带条件的动态分支结构。

image.png

图4.13  函数工作流程四类编排模型

以带条件的动态分支结构为例,函数工作流程组合实现如图4.14所示。

image.png

图4.14  带条件的动态分支结构实现

通过这四类函数间的组合模型,可以编排大部分函数计算的场景。