当前形态
在讲当前形态前首先要介绍下几个基本概念。目前我们的所有业务系统都是严格按照领域做划分和组成的,开发人员需要知道领域、链路和服务这几个概念间的关系和定义,一旦能够明确这些概念定义就能够容易明白业务和系统之间的关系以及系统和系统之间在职责上联系。
交易领域
在饿了么内部交易领域是相对大的范畴,是整个公司最重要的生命链路,所覆盖的内容也并非是集中式的,而是分散在各个系统的职责上。比如客服系统看似和交易无关,但其实有交易职责的,因为它最终会影响到交易的结果。
因此我们定义从用户下单开始一直到订单完成为止,直接影响到最后订单结果的内容都承载着交易的职责。
交易链路
交易链路是完成一笔交易所需要的最短路径,这其中的任意节点都是不可缺失的,一旦缺少某一节点交易就无法达成。一个大的领域往往会有很多条业务链路,一般会有一条是最关键的,其余几条则是业务高点。
交易系统
交易系统相对就比较好理解了,所有的服务以一定的业务为边界具体组成的明确部分就是交易系统。
上图展示了参与交易的主要系统,可以看到除开订单和支付系统之外,还有很多影响交易结果但不承载完整交易职责的系统也在其中,整个交互关系非常复杂。正因为一个交易领域作为交易系统的复杂要求,所以交易系统本身的职责是很容易混乱的。
业务特性和基本划分
为了更清晰的确定交易职责,我们以交易订单为基础拆分出了正向链路和逆向链路两个部分。
上图是正向链路结构图,可以清晰的看到从用户下单、支付成功、系统确认到最后接单完成的整个过程其实是非常简单的一个链路。
实际应用中也会将这个链路做的非常简单,因为定义正向链路所承载的主要职责是让一笔交易在技术和数据层面完好无损的走到最后。
这套服务的系统要求是在系统本身IO、数据的可靠以及稳定性上,一些复杂的业务逻辑不会放到正向链路中。正向链路要保证的是在大流量高并发情况下能够处理的很好并完成每天千万级别调用。
上图所示的是逆向链路,它多出来了仲裁和交易取消申请等环节,逆向链路其实是以所有异常场景处理为核心职责的。它的定义与正向链路刚好相反,正向链路重的是系统本身的可靠和性能,逆向链路重的是所有复杂场景的处理。
我们在所有正常业务的处理过程中,尤其是新增的业务上一定会考虑逆向链路的支持。
服务架构
这套服务架构大概分为三层,最底层为通用服务,这一层在交易领域内的职能和服务能力是应该被大范围复用的。
中间为核心服务层,是所有逻辑的承载,这一层分为交易支撑和交易保障两部分,这样的划分和前面提到的链路其实是相似的,交易支撑承载的是流程职责,而一些业务场景会被单独剥离出来放在交易保障中。
最上层是对接的业务系统,几乎所以涉及到的交易系统都会对接底层的服务。
以这套架构为核心就会发现有大一部分是能够存下来或者是可以复用的。
系统架构
我们的整个交易服务是比较垂直的,它的核心是流程,因为交易其实就是流程不停递归的过程。
整个系统架构的组件并不复杂,主要是Redis和MySQL。通过MySQL进行解耦,以防与其他系统有过多的交互。
当时的问题
在讨论问题之前,首先分享给大家我们团队内部一直在说的一句话。
▶架构层面的一切努力都是为了满足业务的扩展性需要
做业务架构其实是比较务虚的一件事,不像做组件或者中间件的架构那样有着明确的目标。业务需求的时刻改变使得业务架构的方案存在多种可能,结构人员需要在这些方案中选择出对的那个,那么怎么才算是对的方案呢?
我们内部的评价标准是看这个架构能够使用多久,未来的两到三个月是否会消退掉。
遇到的难题
这里将我们在整个架构演进过程中遇到的问题先列举出来。
- 原系统职责庞大,维护和迭代成本很高,需要拆分。但是不知道怎么拆,也很难对怎么拆达成一致。
- 业务越来越复杂,接口和字段越加越多
- 新业务对老业务会造成冲击,兼容永远是考验功力的
- 系统稳定性要求高,不管是新业务上线、老业务迭代、技术改造等,都不允许宕机哪怕一秒。
案例-订单与物流交互服务
订单与物流的交互服务可以说是一个通用的案例,订单服务承载外卖的交易,配送的运营由运单服务负责。
饿了么的交易和物流是两个大的系统,由两个团队分别负责。为了在这两大体系间建立方便的对接,我们设想了一个订单运单交互服务,让订单交易和物流之间的数据交互都通过它做中转。最终我们实现了这样的一个服务,并且把一定的职能从订单服务和运单服务拆分出来。
在实现的过程中我们遇到了新的问题,首先这个交互服务出于性能和数据便携的考虑缓存了一部分的订单或运单的数据直接从接口输出。这样的话交易链路上就多了一个掌握数据的节点,一旦整个链路出现数据不一致或者其他问题,排查起来会相当困难。同时其他各个服务的接入方无法判断接口或逻辑的提供方,需要花费大量的时间沟通。
后来我们发现实现这套服务后整个开发效率反而更低了,最后我们还是将交互复的职责还回订单服务和运单服务。
这让我们意识到如果一个领域或系统的职责是清晰并独立的,那么就应该让它直接被其他各个系统使用。另外对于系统的拆分和领域的识别要有共识,这个共识不仅仅是交互的双方。
案例-新业务的形态支持
在购买饿了么会员时生成的其实是一个虚拟订单,当我们开始接收到类似这样的业务需求的时候是有一点纠结的,因为原有的外卖订单流程有部分是支持该业务的,只不过需要在此基础上做一些兼容,所以当时我们所面临着在建立一套新的系统和在原有系统上做兼容之间做出选择。
最后我们选择新增虚拟订单服务,由业务形态以及当前逻辑的可复用程度决定,尽量服用,拆分(解耦)永远比合并(内聚)容易
整体建议
基于以上所提到的案例,这里做一个整体的建议。
- 一定要有一张完整全面的架构图,以系统的维度标注出核心主链路,确保其始终清晰。
- 花时间去了解业务和它的发展,为未来做准备而不是直接做未来。
- 架构债务比代码债务更难还,评审checklist以及债务总结必不可少。
未来的发展
业务系统的发展往往紧随业务复杂度,但是这里有一个悖论,即如果业务都不知道如何发展,那么业务系统就更别谈发展了。
对此我们有一些思考和实践,主要是在效率和效能方面。效率其实很好理解,就是如何改进架构使得更快的满足业务前进。效能则是在原先系统业务的能力上进行扩展。这两者并非互相违背而是统一协调的,一个好的设计效率提高的同时效能也会随之提高。
基于这样的思考,我们在内部做了一个尝试,把我们对交易的理解付诸到一套系统上。交易无外乎几个形态,物品的交换、信息的交换和能力的交换,往往O2O或电商涉及到的都是类似能力的交换。
上图就是这套系统的整个架构。最上层是导购前台服务,负责与用户的直接交互,是所有数据的入口。中间的交易中台服务核心是合同的管理以及流程和能力的服务。最低层是所有的基础支撑服务,店铺、商品、账户这些资源都是基础服务是交易数据的一部分,基于它们就会产生交易能力然后提供给前台业务。