Flutter和FaaS一体化任务编排思考与设计

文章资讯 2020-08-07 21:28:03

Flutter和FaaS一体化任务编排思考与设计

如何提高FaaS研发体验?
FaaS层通常是直接在主干中逐块增加业务代码,这种写法领域数据间的依赖并不清晰,后续维护时需要针对领域数据进行更换、顺序调整或者由串行改并行时需要增加很多工作。
如何提高FaaS侧研发质量?
客户端同学编写FaaS代码时,需要针对服务端各种异常增加保护性代码与降级策略,比较容易出现遗漏从而导致整体质量下降。
任务编排是什么?
回顾一个完整的业务闭环,包括中台、领域层、业务层与渲染层。云端一体场景下FaaS侧更多的工作集中在业务层与渲染层,进行数据聚合、裁剪、字段映射和结构调整。
以下单业务为例,FaaS层通过6次HSF(RPC框架)调用获取领取数据组装而成。商品信息、收货地址与闲鱼币可以并行执行,红包、运费与验货担保可以并行执行,由于依赖商品信息与收货地址,两组任务需要串行执行。
上图中可以把每一个节点(例如:获取商品信息)抽象为任务,通过代码实现此流程就是任务编排。
任务编排如何提升开发体验?
FaaS层通常是直接在主干中逐块增加业务代码,遇到复杂场景时主干代码可能百行甚至千行,以下是通过任务编排框架编写的下单页功能代码。
通过Map类型的数据作为入参,其中多个任务都可能使用到这些参数。
使用then与thenAll两个API进行任务编排,then函数表示传入的函数串行执行,thenAll传入的函数需要并行执行。
调用apply进行任务链路的执行。
通过链式调用,整体结构非常清晰,框架的侵入性低。
可以看到以上代码入参、任务编排与获取结果,结构非常清晰。从代码上就能看出任务数量、任务流程、任务的串行与并行。通过简洁、少侵入性与链式调用极大提升开发体验。
requestItemDO函数是获取领域数据常见流程,首先是获取参数userId与itemId,通过HSF获取商品信息,拿到结果之后判断此次请求是否有效,如果有效返回具体Model数据。
任务编排的应用场景
任务类型
任务编排并不局限于HSF任务,由于框架仅要求传入的是一个函数,通过函数进行抽象,可以支持任意类型的任务编排,例如:HSF、MetaQ、Tair、DB等。
任务编排形式
下单页的例子是串行&并行共存的场景,任务编排框架支持任意数量串行、并行、复杂场景任务编排。开发同学只需要开发任务函数,然后根据任务需要串行还是并行,调用具体API接口,不用关心同步与异步的各种操作细节。
异步任务
FaaS侧的代码通常都是IO密集型的任务,例如PRC调用、数据库读写等。Dart基于事件队列(Event Queue)支持异步,其优点是可以同时等待多个IO事件,并不会阻塞主线程,从而降低总体RT(Response-time 响应时间)。Dart 异步机制耗时如下图:
任务复用与沉淀畅想
针对FaaaS侧把单个数据的获取与处理抽象为Task,随着Task沉淀的越来越多,通过多个任务的组装会出现业务解决方案层,很多场景下都需要安全校验,例如:判断用户是否禁言、商品是否违规等,这些通用的规则也可以在其他也场景中复用,例如安全校验规则可以在群聊功能中复用。
三端一体研发架构场景下,从数据的获取、组装到前端的UI可以一个开发者完成,整个链路可以如右图进行一体化的组件沉淀,一个组件包含领域数据、转换为ViewModel、客户端视图组件组成,从而形成云端一体的组件复用,提升整体开发效率。
任务编排如何提高研发质量
客户端写FaaS层代码,需要学习服务端QPS(Query Per Second每秒查询次数)、RT(Reaction Time 响应时间)、TPS(Transactions Per Second每秒事务处理量)、限流保护、降级保护与热点保护等,其中最担心的还是如何保证部署到Serverless平台上FaaS层代码的稳定性,如何才能提高质量不出现问题与故障。可以通过异常分类、如何捕获异常与异常处理三个角度来分析质量问题。
异常分类
首先总结下服务端常见异常类型:
代码异常:空指针异常、数组越界等Exception
系统异常:机器异常、内存溢出、线程池占满、DB异常等
接口异常:接口响应超时、下游依赖异常
异常捕获
无论FaaS层出现哪种异常,不能因为异常而导致用户长时间无法正常使用功能,需要考虑异常捕获,并设计整体的降级、监控与告警方案。通常服务端开发都是通过在可能出现问题的场景添加try catch,这样代码写起来不够简洁,开发同学更期望看到像上文中queryItemDO函数一样,只编写业务功能代码,至于捕获、通用监控与告警,由任务编排框架进行统一的兜底处理。
任务编排框架把捕获的异常信息通过两种方式传递给开发同学,一种是针对单个任务的onError,一种是针对整个链路的catchError,通过这两种方式可以优雅的获取异常堆栈并进行灵活的异常处理。
通过针对调用链路设置整体超时时间,避免因任务的等待超时而导致整个接口出现超时的情况。