微服务(SOA)的编排与编制及组合的分析与实践

最近在开发公司产品的核心主业务,因为此业务需要串起多个子应用,子应用都已经独立部署,而且拆分的独立应用非常多。比如企业任务子应用,订单子应用,任务执行总控应用(内含很多个子任务执行子应用),签章子应用,支付子应用,未来还有核算子应用,报告子应用。
在这样一个核心业务中的各相关应用调用中,有可能中断被介入,也可能部分必须同时完成,也可能应用宕机等情况。笔者之前一直做单体应用,刚从事互联网业务,才面临这些问题。如何把这些服务合理的整合在一个业务场景中,这是我一直在思考的一个问题。

虽然第一个版本已经上线了,但时间仓促,在目前的进一步重构优化中,需要很好的把握多个微服务的调用。虽然网上很多微服务编排的文章,还有多个微服务的分页式事务,但貌似不解决我的业务问题,还有些文章一知半解,到处复制。最近又看到网上的两个文章,基本上心里有思路了。

[size=large][b]一、(微)服务相关概念与关系[/b][/size]
标题中的编排与编制来自后面附的文章。
“编制的英文是Orchestration,本意是乐队指挥。微服务的编制强调的是通过一个可执行的中心流程来协同内部及外部的服务交互。通过中心流程来控制总体的目标,涉及的操作,服务调用顺序。”
“编排的英文是Choreography。微服务的编排强调的是协作,通过消息的交互序列来控制各个部分资源的交互。参与交互的资源都是对等的,没有集中的控制。”

提到微服务技术,少不了以下一些概念,先分成几类:
[list]
[*]与外部有关的概念:注册、发现、监控(可以没有)
[*]与本身有关的概念:熔断、限流、降级、超时、重试、幂等(部分可以没有)
[*]与组合有关的概念:最终一致性、分布式事务、CAP、BASE、补偿、分布式锁
[/list]

而分析上面的业务应用功能:我们目前没有注册、发现,没有熔断、限流、降级。应用之间可能有重试、幂等要求。

应用之间的关系:有两种情况。比如中间有环节可以被中断,比如账户钱不够就中断到某个状态。重新再支付再运行。所以这时也没有自动重试,用户可以介入。也有的应用之间是强关联,比如订单支付成功与账户金额变化,这两者之间一定要最终一致,重试与幂等,中间不可能产生有用户介入的操作。对用户来说,要么成功要么失败,用户不会知道中间状态的。
如果两个应用之间是弱关系,其中一个应用down机了,既然有用户介入,是不需要维护一致性的。如果后面的强关联,是一定要维护一致性的(自动或者人工后台干预)。

我们这些业务系统,到底是soa吗?业务是微服务吗?貌似情况比较多。

[size=large][b]二、设想两种极端的调用[/b][/size]

[b]串行调用方式:[/b]
如果企业任务应用接受一个外部任务开始,只调用订单子应用。而订单其内部调用签章子应用,签章内部再调用支付子应用,支付内部再调用执行总任务,执行总任务调用核算子应用...再一层层回溯回来。对外层来说,只调了一个应用,其它都被代理了。也只有一个状态:订单的状态。

[img]http://dl2.iteye.com/upload/attachment/0129/9632/04cd1107-856b-30d8-9cff-4463d9f29bd1.jpg[/img]

一个明显的问题是,如果很多内部状态要显示给用户,而且用户可能进行介入操作。如果第一层要记录下每个层的状态,层次稍微深一点就非常复杂了。最深一层的状态变化,都要向上冒泡到最外层。比如任务调用了订单,订单调用了执行。外层的任务很难显示执行的状态,只知道订单提交,订单成功或者失败。因为执行完全由订单应用代理了。
另外,如果用户介入到深层次的操作,外部除了显示内部状态,还要层层把请求转发到相关层,复杂度,失败可能性,失败的处理都非常困难。
如同生活中找代理公司办事,人家可能一层层找人做,你只能看到最终的结果,如果去打听一层层的进展,将是非常困难的。一般会说,你等着,最后结果会告知的。后面也许还有他不掌握的层层调用,代价很大,怎么可能提供外部详细的调用状态呢。如果想办法找到了某层代理人,要介入,人家也不认识你,人家只认上层调用他的人。

[b]中心总控方式:[/b]
这在生活中非常常见。比如我们去医院体验,有一个体验表,每个任务都有一个填写块,都完成了就总检。如果有没完成的,第二天再去,也许有步骤可以跳过。再比如一个建设项目,要很多个部门审批,公司肯定有一个项目进展表,规土局,建委,环保局,一个个进展都记录下来。

[img]http://dl2.iteye.com/upload/attachment/0129/9634/9604e2cc-f2e0-35e2-aa8b-afbe4bcfc91c.jpg[/img]

不可能你去规土局办事,规土局一门受理了,最后由机关内部流转到建委、环保局,最后你从规土局口子拿到一串部门办好的结果。

[b]组合方式:[/b]
设想在中心总控的方式中提到的公司的项目进行审批,你得到的状态是一个个部门的受理、办结。而你得不到部门内部的受理环节、科审、处审、办结等具体环节。部门之间你可以介入再发起、部门内部你完全无法介入,如果科审失败就整体失败返回,重新从受理开始。
用户对服务的调用发起,只能从可介入的服务开始,比如各个部门的受理。而内部要么成功要么失败,中间是不能由用户介入的,用户通常也不知道内部的进展环节。

[img]http://dl2.iteye.com/upload/attachment/0129/9636/ef42e100-4438-3192-a4ea-408ce3524296.jpg[/img]
如果一个部门的处长审核时认为缺少资料不通过,结果会是本部门办理的整体审核失败,不会在此环节由企业介入补材料。企业可以下次重新受理,也可以不办理了。

[size=large][b]三、结论[/b][/size]

我的业务要求在给用户展示出几个重要环节的状态给用户介入,比如钱不够会停止在订单,用户可以再支付。授权时,如果没收到授权,用户可以介入再发起。核算中如果再付款,用户可以再支付。然而有些过程,比如用户帐户有钱,那订单状态与账户扣费及发票都是一起发生的。这几个又有最终一致性要求,不会给用户显示中间的状态。

所以合理的设计,强组合在一起的业务,可能由一些应用发起,对调用方只返回结果,内部保证最终一致性,这里没有中心,是完全去中心化的。而这些强组合的进一步组合出更大的弱业务流程,中间可正常中断,就需要一个总控,显示某个强组合的状态,这个状态的用户所介入的操作,将启动强组合业务。

用字母表示应用,应用的组合类似于: “-ABC-DE-F-G-HIJL--”。如果一切顺利,可以从A调用到L不失败,如果中间有问题,只能停留在“-”的状态由用户介入。"DE"是强组合,成功就到F,不管DE哪一个失败,停留在D前的状态。D成功E失败,D可以不断重试,直到超时D回退。比如订单修改了状态与库存,再调用扣费,结果没调成功,反复重试还不成功,订单状态就要回退。如果先扣费,再修改状态与库存,修改出错,扣费就退款。反正必须同时成功;反正不用用户介入。

这样,我们要合理划分业务流程中的各应用之间的关系。数据库中主业务数据表的状态有一个总控状态,只记录在弱组合中的结果状态。应用强组合之间进行超时、重试,幂等,回退等,只有整体成功与失败。

[img]http://dl2.iteye.com/upload/attachment/0129/9638/53788a37-47a2-37ef-9bdd-331abd28f091.jpg[/img]
此图中,小黑块是一个个服务,服务会有一定的强组合,就是最终一致性,而整体的业务会串起单一的或者组合的应用。强组合内不存在用户可介入的分支(如果重试、超时、意外的不一致,由后台管理介入)。
我们的业务是整体的由中心控制的编制,与局部无中心化的编排的复杂的结合。

[size=large][b]四、感悟[/b][/size]

微服务确实很微。完整的业务往往是一些组合情况。高聚合低耦合的原理无处不在。高聚合的微服务就是要研究编排,一致性,分布锁等。低聚合的微服务就是要编制,为了灵活可以参考工作流的原理进行统一配置。

附参考文章:
https://blog.csdn.net/jessise_zhan/article/details/80129818

https://blog.csdn.net/wp94302948/article/details/79653945

你可能感兴趣的:(微服务(SOA)的编排与编制及组合的分析与实践)