本篇主要介绍交易中台如何做到高可扩展性,通过对在线交易业务梳理分析,可以发现变化部分主要来自两个方面,一方面是交易流程的不同,如虚拟商品交易流程就非常简单,而大家电类的交易流程就比较复杂;另一方面是来自交易流程环节中具体执行不同,如:地域限购, 有些业务是全国可售,有些业务只能是部分区域配送,作为中台,需要开放这些能力让业务自定义自己的能力。

因此我们将聚焦在流程和基础能力可扩展性上,对于流程的可扩性,需要能够按照业务来编排交易流程,自然是会用到流程引擎的技术。对于基础能力来说,更重要的是业务中台模型的抽象,预留能力扩展点,技术上使用osgi的扩展点模式。

交易流程编排:

前提:

交易中台划分了两层,交易流程编排是在平台层。能做流程编排的前提是,交易基础能力层已沉淀完毕,这个在前面的文章已经介绍过了,不在重复说。

为了能够将流程引擎和基础能力层无缝的结合起来,还需要适配层,对此我们抽象了交易组件来对基础能力做封装,统一适配到流程上。组件类图如下:

IProcessor 接口抽象流程执行中的正向和回滚逻辑。TcComponent 类为交易组件类,所有的能够嵌入到流程中作为运行节点的交易能力,都必须适配成TcComponent,TcComponent类将业务行为和组件标识等组合为一个完整的业务单元。其具体的业务组件必须继承TcComponent。

以拆单组件OrderSplitComponet 为例,该组件需对交易基础能力的拆单能力进行封装,封装拆单业务的正向和回滚逻辑,以支持流程引擎的正向调用执行和失败后的逆向业务回滚调用。

流程引擎:

流程引擎选择的比较多,如jbpm,activiti 等。这些引擎相对功能比较完善,有图形化的操作界面,但也比较重,运行效率不高,在OA领域使用的比较多。对交易来说还是更追求性能,多方对比后我们选择了apache camel 作为流程引擎。关于camel的介绍,更多参考http://camel.apache.org/

有了适配层的抽象,我们就将TcComponent作为camel 中的EndPoint. 利用camel的规则引擎进行流程的运行就可以了。

流程编排工具:

对于需要支撑很多业务的中台,需要提供图形化的交易流程编排工具,用来辅助完成流程的编程,工具需要集成交易的基本参数,流程节点就是交易的基础能力的代理,有了适配层,就直接对应交易组件TcComponent。同时也需要统一管理流程的发布,下线 和业务绑定。

图形化的流程编程工具需要结合公司的实际情况进行自行研发,研发成本比较大,如果业务体量不是非常大,使用一定规范的配置文件,数据库配置代替就可以了。

路由和运行:

一旦流程编排完成发布和业务绑定后,交易系统加载后,每次的交易就会触发运行。运行时可以根据业务参数,动态路由出交易流程,调用流程引擎进行执行。

流程一旦启动执行,会将交易对象作为上下文参数,每个节点必须要实现IProcessor 接口,该接口有个一execute()方法和一rollback()方法。execute()要在设计上支持幂等。rollback 方法时在流程中任务一个节点处理过程中,发生异常,都需要调用的业务回滚,回滚接口同样需要保证幂等。整个流程引擎在异常的处理机制需要非常健全。

public interface IProcessor {
/**
* 正向执行时调用方法,需等幂处理
*
* @param t
/
public void execute(T t) throws Exception;
/
*
* 业务回滚操作,需等幂处理
* @param t
*/
public void rollback(T t);
}

InventoryOccupyComponent 的两个方法(示例代码):

@Override
public void execute(OrderContext context) throws Exception {
List list = buildOccupy(context.getOrders());
Result result = null;
try {
result = innventoryPAService.occupy(list);
} catch (Exception e) {
LOGGER.error(“占用库存失败", e);
throw new Exception("占用库存失败", e);
}
if (!result.isSuccess()) {
Integer code = result.getCode();
//异常处理
throw new Exception();
}
@Override
public void rollback(OrderContext context) {
List list = buildRollback(context.getOrders());
try {
Result result = innventoryPAService.batchRollBack(list);
if (!result.isSuccess()) {
//异常处理
}
} catch (Exception e) {
//异常处理
}
}

在流程运行时,我们是利用camel的Dynamic Router 来作为流程驱动的引擎。

关于Dynamic Router 参考http://camel.apache.org/dynamic-router.html

在运行时,任何一个节点都会出现异常,因此需要整体的流程异常处理机制,从发生异常的节点,逆向执行调用组件的rollback接口,因此rollback接口的设计也非常重要,对于不能做业务回滚的操作,需要在业务方案上有预案。

扩展点机制:

前面的文章已介绍,抽象和沉淀交易域的基础能力,对于这些能力中容易变化的部分,需要设计一套机制来应对将来变化的扩展,能够让不同业务自定义。在处理变化上OSGI的扩展点思想是非常好的案例,交易中台也采用扩展点来扩展自己,交易的基础能力在设计阶段就需要提前甄别出变化的部分,将其抽象成扩点,供个性化扩展。以区域限购这个交易能力为为例,来举例说明,区域限购 其中一个重要的逻辑就是根据收货地址,来判断是否支持该区域的销售,不同类目对其判断差异非常大,像中小件的类目,几乎全国可售,对于大件,生鲜类目来说,需要根据自己的仓库和供应链能力决定其区域能不能销售,对此我们设计了BuyAreaLimitExtPoint 扩展点来让不同的业务来进行扩展,同时也提供了默认实现,解决大部分类目的共性问题。

因将扩展点开放给业务团队,随后面临的问题就是,交易中台如何有效的统一管理不同团队贡献的代码,如何去隔离,防止冲突和相互影响。在这块我们做的不是非常好,目前只是通过为不通过的业务单元建立不同的package 进行代码隔离。好的做法是业务团队的扩展点,通过独立的jar包 引入到交易中台。

交易逆向的处理流程和正向流程完全一致,不同的只是流程类型不同,入口不同。

更多文章欢迎访问 http://www.apexyun.com/

联系邮箱:public@space-explore.com

(未经同意,请勿转载)