如果让前端应用开发来处理这种事情,又变成了需要大量编写脚本代码,而且存在共性领域服务逻辑对外泄露的问题。
服务编排实际上就是对基础的业务处理流程,步骤,规则逻辑进行封装,然后提供一个封装后的组合服务或领域服务API接口能力给前端应用开发。这个和传统SOA架构里面谈到的通过BPEL来进行SOA服务编排思路完全一致。
当前微服务编排引擎来源
对于开源的微服务编排引擎,最早大家比较熟悉的是Netfix Conductor,我在前面也专门写过文章分析和说明,但是这个开源版本本身更多的是面向开发人员使用,很难做到前端的可视化灵活配置,而且也没有可视化设计能力,只有编排完成后的可视化监控。
从当前主流的一些微服务编排引擎来看,主要包括如下几类发展演进。
其一是从传统的工作流引擎或BPM引擎积累开始做微服务编排引擎,比如当前开源的Zeebe,其开发团队即来源于知名的Activiti工作流和BPM引擎。
其二是传统的ESB服务总线上层,对于ESB总线本身就有轻量服务编排功能,因此从ESB总线来发展微服务编排引擎。
其三是基于分布式任务调度系统,自动化事件事物触发编排发展出来的微服务编排引擎,要明白微服务编排最终核心仍然是各个活动或任务的处理。类似当前在物联网领域应用广泛的Node-Red编排引擎属于这种方式。
如何理解微服务编排场景?
当我重新思考这个问题的时候,进一步将编排场景进行分类理解。
首先第一类就是简单的服务组合,服务拆分,数据裁剪,数据映射等,这些内容可以通过服务编排来解决,比如输入一个供应商编码,同时调用两个API接口服务,一个是查询供应商基本信息,一个是查询供应商的订单明细列表信息。在调用返回后将结果整合为一个Json输出给调用方。
对于这类场景实际就是对应到传统ESB轻量服务编排能力,并不涉及到复杂的业务规则,业务逻辑处理,也不涉及到类似BPEL自动化业务流的处理等。
其次是基于业务处理流程的多个服务编排处理,这个场景和传统SOA架构里面的BPEL很类似,就是要完成一个业务功能,你会发现本身就需要调用多个接口才能够完成,而且这些API接口调用本身有先后关系,有调用逻辑和分支判断,上游API接口服务的输出往往会变成下游API服务的输入,形成核心的串行逻辑结构。因此你需要通过一个编排功能将多个服务编排在一起,最终暴露一个服务。
对于这类场景一个典型就是一个前端功能实现,当完成相关书籍录入后,点击一个按钮触发事件,传统代码开发方法一定是在按钮触发事件方法中编写具体的代码实现逻辑,这个逻辑本身也涉及到调用多个API接口服务,当然也存在分支判断逻辑等。
而新的低代码开发或Serverless无服务器化下,我们更加希望点击代码只需要调用一个编排完成的组合服务能力即可。前端开发人员并不需要知道内部多个API服务编排组合的规则逻辑。那么这个场景下就需要先通过微服务编排引擎形成一个组合服务API,然后再暴露给前端应用使用。
我们最近做了什么事?
最近在实现微服务编排能力的时候,前期也进行了大量的选型,最早的计划是整体从零开始,基于已有的图形化设计器的基础来做服务编排引擎。
但是分析完成后整体从零开始做仍然难度不小,不仅仅是API服务本身的组装,拆分,规则逻辑处理,更加重要的是需要底层有一个完整的任务调度引擎或事件处理引擎。对于消费方系统来说看到的是一个组合服务API,但是其内部本身是多个服务组装,组合完成的,内部已经变成一个消息或事件驱动的异步处理系统。
因此在这个过程中你需要去处理任务调度,处理异常容错,处理分布式事务和回退机制。所有的这些底层逻辑要从零开始实现本身还是有一定难度的。
Node-RED是一种基于流的编程工具,它有一个可视化编辑器,允许将节点连接在一起创建流。满足微服务编排最基础的可视化服务编排需求。Node-RED最初是IBM在2013年末开发的一个开源项目,以满足他们快速连接硬件和设备到Web服务和其他软件的需求——作为物联网的一种粘合剂,它很快发展成为一种通用的物联网编程工具。
因此通过选型后,最终选择了Node-Red来实现微服务编排,当时我们规划的接口服务串行,并行,数据合并整合,规则处理,异常捕获,日志记录等需要都能够实现。
整体来讲Node-Red应对简单的服务组装,组合没有任何问题。但是如果存在类似BPEL一样的自动化业务流处理,仍然不合适。毕竟Node-Red这个开源项目诞生的目的仍然是为了应对物联网领域常见的任务和事件处理,重点是多个任务或事件的编排而非类似业务系统功能开发中的流程编排。
微服务下Http API接口编排关键点
我们这里谈的微服务编排更多的是指对微服务暴露的Http API接口的可视化编排和组装。这个是谈论这个点的前提。
对于微服务编排引擎底层前面已经谈到重点是消息中间件,分布式任务调度和执行逻辑,状态机等。那么在这个底层逻辑上面进行微服务API编排的时候还需要具备或扩展哪些关键能力,初步思考如下。
其一是对于Json格式的处理。
也就是服务编排中会经常遇到Json格式的拆分,合并,数据映射等操作,一个编排引擎必须在这个方面相当灵活。Json格式的字符串本身也是存在规则,是可以模板化的,只有模板化后才方便进行处理。同时一个Http接口调用本身存在输入,输入的内容在后续多个编排节点都可能使用到,因此还需要支持输入信息的参数化处理。
这些参数对于整个组合服务运行实例中的全局参数,在后续任何节点都可以引用到。
比如当获取订单信息的时候,我们希望同时返回订单对应的供应商的基本信息。也就是先调用获取订单信息,拿到供应商编码后再去调用获取供应商信息,最好将供应商信息结果拼装到整个订单信息中返回。
- //调用GetOrderInfo获取Order信息
- //根据返回的supplierid发起对GetSuplier接口调用
- //将返回的信息作为子对象拼装到完整Json里面
- orderInfo
- {
- orderid
- ordername
- supplierid
- {
- suppliername:
- suppliertype:
- address:
- contactphone:
- }
- }
可以看到,编排的时候同时调用多个API接口并不难,难的地方是如何完成结果的映射,快速,灵活的组装,这个能力反而更加关键。
在传统的SOA服务编排里面,经常会采用类似Xslt模板来完成数据的映射,组装等操作,这种参数化模板映射的思路完全可以借鉴。
其二就是业务规则和逻辑处理
在常规的SOA服务组装中,一般会将BPEL和规则引擎结合,来实现复杂业务规则和逻辑的处理。而对于微服务编排,本身就是一种偏轻量的编排,不适合处理过于复杂的业务规则和逻辑。
因此服务可视化编排中,能够支撑最简单额分支判断逻辑,条件组合逻辑就可以了。而对于更加复杂的逻辑建议是单独先实现一个规则处理的原子服务API接口,再应用到微服务编排中去。
对于低代码开发平台的应用,我在前面也提到过这个观点。
即首先低代码开发平台应该是基于服务分层的思路,将前端开发和后端服务能力区别开,通过服务层来彻底解耦。其次就是在服务层提供可视化服务编排能力,提供编排后的组合服务给前端应用调用,减少前端应用调用难度。
但是如果出现了复杂的业务规则处理逻辑,这个就不要在服务编排里面去处理,还是单独实现一个规则处理API接口服务,再暴露出来给上层应用或编排设计器使用。
其三就是分布式事务处理机制
由于将多个微服务API接口服务编排在一起,一定会产生分布式事务问题。
当前的编排技术实际本身又为了完全同步等待的方式和异步类似任务事件和状态机处理机制。在前面我们谈到两个场景。
如果是简单的服务组合,拆分,可以用同步模式。但是如果是类似业务流程处理的多个服务串行编排,建议是采用异步任务事件处理机制。底层也需要消息中间件和中间态数据的存储机制来进行支撑。
实际在微服务编排里面的分布式事务处理,最佳的方式仍然是基于幂等规则下的事务补偿。
我们一个最简单的例子。在订单保存的时候需要扣减库存。
这个时候涉及到SaveOrderAPI接口和FreezeStockAPI两个接口,对于扣减库存有一个对应的逆操作接口ReleaseStockAPI。
那么你在进行微服务编排的时候实际需要将这三个接口都编排进去,而且还需要增加判断规则逻辑,即当SaveOrderAPI失败的时候进行ReleaseStockAPI,库存扣减回退操作。
那么是否有一种方式将这个过程简化。
即涉及到分布式事务的场景,我们对任何一个API接口服务都需要同时配置这个服务的逆操作回退API接口服务。那么当下游服务操作在出现异常的时候,由整个微服务调度机制通过调研逆向API接口,自动发起多上游服务的回退操作。
如果回退操作仍然失败,那么发送异常处理通知或邮件,通知人工介入操作。
第四点是微服务链路监控
在谈微服务的时候经常会谈到微服务链路监控,简单来说就是前端是调用一个按钮处理,但是按钮方法的实现逻辑里面可能会调用多个微服务API,因此需要对整个链路进行监控,以方便进行性能问题分析,异常问题排查。
在使用微服务编排后,按钮原来的处理逻辑已经转换到微服务编排和设计里面去完成。一个编排后的微服务在内部可能会调用多个微服务API接口,形成微服务API的接口调用链。而这个内容仍然需要提供完整的监控,日志查看能力。
这个和工作流引擎里面的流程监控类似。
即微服务编排完成的也是一个流程,是自动化的业务流,中间调用多个API接口服务,因此需要对整个自动化业务流做到端到端监控。通过微服务流程实例进入后,能够详细看到当前执行到哪个环节,如果出现异常也能够快速地排查到具体的错误异常日志。