微服务架构的系统中存在着大量的服务编排,常见的有三种模式:
- Orchestration(编制):通过一个可执行的流程来协同内部及外部的服务交互,通过流程来控制总体的目标、涉及的操作、服务调用顺序。这种模式必须有一个流程控制服务,用来接收请求,组织服务间的调用,并最终完成业务逻辑。这种方案中大多是同步调用,虽然在某个时刻能够很清晰的知道服务的执行情况,但当业务复杂,服务很多的情况下,在控制服务中会存在大量的耦合,难以维护;
- Choreography(编排):通过消息的交互序列来控制各个部分资源的交互,参与交互的资源都是对等的,没有集中的控制。可以看作一种消息驱动模式,或者说是订阅发布模式,不同的服务之间通过消息机制串联起来,这种方式大多都是异步的。好处就是耦合度低,但也会带来一些问题,比如:业务流程是通过订阅的方式来体现的,很难直接监控每笔业务的处理,因此难于调试;由于没有预定义流程,所以很难在事前保证流程正确性,基本靠事后分析数据来判断等;
- API网关:API网关是一种简单的接口聚合/拆分的方式:业务组件的请求后先到达网关,网关调用各微服务,并最终聚合/拆分需反馈的结果。API网关其实就是一个适配网关,比如对于 Web端,可以一个页面同时发起几十个请求,而对于移动端,最好是一个页面就几个请求。而采用API 网关,后面的微服务可以是相同的。但只能应对一些逻辑简单的场景。
结合上面方式各自的优点,Biz-SIP中间件实现服务编排的实现思路如下:
- 一个应用服务可以拆解为一个或多个原子服务,每个原子服务可以抽象成一个通用模型;
- 每个原子服务提供 API 接口;
- 对原子服务接入提供基于配置的通讯接入适配和消息格式适配,支持多种原子服务接入方式和原子服务调用方式;
- 提供针对服务的全生命周期事件监听机制,实现分布式事务;
- 同时提供同步的服务编制和异步的服务编排;
- 提供标准的API网关,并支持二次定制。
在领域驱动设计DDD中,把整个系统分为适配层、应用层、领域层和基础层,Biz-SIP中间件的source层、app层、sink层分别对应上面的三层:
所有的应用服务,都是在应用层进行封装的,在Biz-SIP中称为app服务,每个app服务都有自己的入参和出参,在一个服务编排的请求上下文中会随着执行的阶段不同,动态组织参数,来调用不同的原子服务(sink服务)。
所有的原子服务,都是在领域层进行封装的,在Biz-SIP中称为sink服务,sink服务只做一件事情,通过一个sink服务或多个sink服务,可以组装出来各种不同功能的app服务,通过app服务的服务编排,让sink服务之间彻底解耦,以便能够灵活组装。
随着服务的增多,调用链会变得越来越复杂,当一个应用服务(app服务)编排整个处理完后,调用链会形成一个复杂网络,这对排查问题造成很大的麻烦。我们采用全链路跟踪来解决这个问题,在一个完整的应用服务调用开始时,会生成一个唯一 traceId,存放在中间件标准报文头中,这个 trancdId 会一直存储在调用上下文中,每个app服务中traceId相同。
sink服务可以被同步执行,也可以被异步调用,这个在sink服务的配置文件中,分别是采用rest和rabbitmq类型来实现的:
- id: sink1type: resturl: http://bizsip-sample-sink/sink1converter:type: simple-jsonconnector:type: sink-beanclass-name: com.bizmda.bizsip.sample.sink.controller.CrmServer- id: sink15type: rabbitmqexchange: exchange.dircect.bizsip.sinkrouting-key: key.bizsip.sink15converter:type: simple-jsonconnector:type: sink-beanclass-name: com.bizmda.bizsip.sample.sink.controller.EchoServer
假设现在用户已编排了一个复杂的业务,当某个环节出现问题时候,我们需要保证数据的最终一致性。常用的一种方式就是提供补偿机制。
Biz-SIP补偿模式,是采用延迟服务的方式来实现的,核心思想是:在系统出现异常后,会触发一个封装好的延迟服务,对原有已经完成的操作进行补偿(撤销)操作,并且能约定这个延迟服务的重复调用次数和间隔时间。
Biz-SIP的延迟服务,能很好地支持向前补偿和向后补偿。
Biz-SIP官方网站:http://bizsip.bizmda.com
Gitee:https://gitee.com/szhengye/biz-sip