项目介绍

本结算系统的目的是为大平台提供支付能力,打通支付渠道,以及支付后续的记账抛帐支持。

业务场景:

1.付款

2.收款

3.对账

4.记账抛帐

针对上面四个业务场景,我们将系统设计为如下架构

c 支付系统架构 支付系统设计方案_数据

其中订单服务和账单服务是两个基础的服务,订单数据和账单数据的持久化都要调用这两个服务的接口。

第三方接入模块里面封装了调用第三方接口的代码

产品执行器是执行不同支付产品的代码

技术支撑模块里面包含了我们用到的所有数据存储介质和中间件

api层包含了我们请求接收层面的所有组件,请求在该层进行前置处理

公共流程设计

1.请求流程:

  

c 支付系统架构 支付系统设计方案_redis_02

1.所有的请求都从gateway中进行权限校验,包括token校验,参数的加解密

2.在产品路由器中会根据请求中的productId字段选择要使用的支付产品。针对于产品路由器,它将后端连接的不同渠道产品重新归类,设计成我们结算系统的产品类型,并统一提供封装。

3.当一条请求所需要的支付产品确定之后,该请求就会被扔到对应的处理器中,这里有同步和异步两种方式。异步的请求会被扔进mq中,同步的请求会直接进入对应处理器。

这个模型奠定了本结算系统的请求模型,所有的请求都要走这个模型进行流转。

2.回调接收流程

c 支付系统架构 支付系统设计方案_c 支付系统架构_03

回调分为两部分:

1.第三方回调结算系统

这里只区分两种回调接收器,一种主动拉取的pull和一种被动接收的push。获取到回调之后立即改变订单状态并推送mq,让后续的业务回调器接收到mq消息通知我们的客户。

2.结算系统回调给平台子系统

它是步骤1的后续步骤,如果这个支付请求为其他平台调用结算系统能力发送出去的请求,那么当支付成功时结算系统理应通知真正发起请求的系统。业务回调器会监听mq中的一个topic(这里没有使用tag的原原因是为后面回调消息的扩展留出空当),每当监听到有消息便会将消息主动推送给业务系统。

 

网关设计

本系统有两处网关:

1.在网络入口处有https网关,只允许https请求进入。https网关之后传输全部采用http协议,避免443端口的占用和资源损耗。

2.请求经过https网关之后会路由到gateway应用网关,在应用网关层面会进行token校验和路由转发,将鉴权完的请求转发到产品路由器中。

ps:由于外网传输过程中采用https协议,那么信息在外网传输过程中的安全性可以保证,再加上我们的token体系,安全性不需要过多考虑。

产品路由器设计

产品分类体系

我们将本系统所有的功能全部设计成一个个的支付产品,每个产品代表一个功能。比如转账功能,这就是一个产品,用户发请求时根据产品选择对应的功能。根据我们的业务分类,我们的产品也主要分三个大类:

1.付款型产品

2.账务型产品

3.收款型产品

每种产品下面还会根据渠道的不同有二级分类,如付款型产品下面会根据渠道分出三个二级类型:

1.xx通付款产品

2.工行付款产品

3.建行付款产品

每个二级付款产品下会有三级产品,这个产品就会细化到某个具体的产品,我们目前的产品规划如下:

c 支付系统架构 支付系统设计方案_字段_04

我们将各个渠道的支付产品和我们的自有产品统一编排后形成了我们自己的产品体系。用户每次请求时都会根据产品编号路由到不同的处理器中执行对应逻辑。这样可以让各个功能保持独立,并且后面在做权限控制的时候可以更加轻松地构建出权限体系。

支付产品存储设计

由于支付产品是树形的结构,所以在存储上有一定难度。这里推荐一种存储树形结构的方案,可以做到快速插入,快速查询而且复杂度也不算太高。

首先在redis中新建一个key,value初始值为0,这个key作为我们的计数器,用来记录每个树节点的编号。

再在数据库中新建一张表,只需三个字段,id,path,content,并且初始化一条数据。

c 支付系统架构 支付系统设计方案_数据_05

c 支付系统架构 支付系统设计方案_c 支付系统架构_06

数据插入:

1.执行redis的incr,获取当前要插入元素的编号,假设为a。

2.要插入到哪个节点下面,就获取那个节点的path,path后面拼接a/作为当前要插入节点的path。

3.在数据库中存储当前节点的内容和第二步中获取的path。

c 支付系统架构 支付系统设计方案_c 支付系统架构_07

数据查询:

1.查询某个节点的子节点

先根据content取到这个节点的path,再查询path列以取到的path开头的所有数据。这些数据就是这个节点的所有子节点。

2.查询这个节点是第几层

根据content找到path,只需要看path中有几个/即可

此方法类似linux中的目录结构的实现,使用此方法插入和查询效率都不错并且复杂度也不高,推荐大家使用。

我们的产品存储设计,相比上面的方案多了一些业务字段,我们的表结构如下:

c 支付系统架构 支付系统设计方案_redis_08

在我们的设计中多了消费方式和消费路由关键字字段,用来快速找到对应的消费者。

产品路由器详细流程

产品路由器项目在启动时会将数据库中的所有产品信息全量同步到redis中(redis中采用hash形式存储各个产品),后面会以接口的形式提供增量新增产品的功能,每新增一个产品会同步更新数据库和redis。

产品路由器接收到应用网关推送过来的数据后,会先去根据productid到redis中寻找对应产品,确定该产品的消费方式和消费路由关键字。

1.如果是异步mq类产品,会将该请求内容发送给mq

在这里我们采用的是一个topic中的不同tag来隔离不同类型的消费者。异步产品中的消费路由关键字是mq的tag,产品路由器取出消费路由关键字后根据其内容给消息打上不同的tag

2.如果是同步类产品

同步产品中的消费路由关键字是要请求的具体执行器url,产品路由器取出消费路由关键字后会将请求转发到对于的url,交给执行器处理

第三方模块接入设计

该模块统一封装第三方的接口,由于第三方接口总会有一些加密,解密,鉴权的代码,这些代码有时候会非常的繁琐,本模块的作用是对这部分代码进行封装,在调用时不需要进行加密解密等操作。直接暴露业务字段供调用方使用。该模块最好以依赖的方式集成到各个产品处理执行器中。

产品处理执行器设计

产品处理执行器也分为两种

1.mq消费者

通过监听不同的tag来响应不同的消息。

2.rest接口消费者

提供rest接口来接收对应的请求,一般是用来同步响应的。

产品执行处理器的逻辑可以由各个模块自行实现,但是有几点比较重要的设计需要说在前面。

1.本系统采用基于状态和tcc补偿的柔性事务构建,状态的流转是该系统的核心逻辑,每次状态的变化都可以将变化通知发送到mq中,对该状态感兴趣的消费者即可订阅这一类消息。目前基本上所有的支付系统都是基于状态来做的,因为基于状态可以更灵活的在流程之中嵌入逻辑,类似于spring的aop,只要找到切点就可以

2.本系统在异步处理的支付产品中将异步处理提前了,在应用产品路由选择器校验完参数之后即可返回,而没有等待传统意义上向第三方支付渠道提交请求后才返回。异步提前可以提高用户体验,更快速的响应用户