9

从无到有,支付路由系统升级打怪之路

 3 years ago
source link: https://studyidea.cn/pay-route
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Hello,大家好,我是楼下小黑哥~

今天继续分享支付系统相关的内容,这次分享一下如何支付路由系统实现方式。

其实这个话题去年也写过,不过当时没啥阅读量,这次就再次翻出来加工一下,炒下冷饭。

支付路由系统

提到路由,不免会想到网络通信过程中起到数据包转发的路由器。

图片来自网络

而我们今天讲到支付路由系统,也是起到类似的作用。路由系统本身并不处理具体业务,它的作用就是将支付请求转发底层支付通道。

支付路由系统

如上图所示,支付系统接入层,接收到支付请求之后,经过内部运算,最后将会通过路由系统转发给具体底层的支付通道。

另外,除了路由转发功能以外,路由器一般还会有一些额外的功能,比如防火墙等。

那我们其实也可以在支付路由系统加入额外功能,比如实时计算底层支付渠道的成功率,若低于一定的阈值,进行报警并且将该渠道下线。

这里需要说明一点,这里的路由系统可以是一个应用中子模块,也可以是一个单独子系统。

为什么需要路由系统

看到这里,可能会有一些小伙伴会思考,一定需要这个路由系统吗?直接将请求发给支付通道不好吗?

答案当然是可以的,如果当前只对接一两个支付渠道,这么做没问题,并且也推荐这么做。

这个阶段由于业务量不大,支付系统可能只是一个单体应用,或者也可能是其他应用内一个子模块而已。

100

那这个时候,业务很简单,系统也很简单,那我们不需要额外的路由系统,增加系统复杂度。

不过这样的系统弊端也很明显,如果后期再新增一个支付通道,我们需要再开发对接。

另外由于所有实现都在一个系统,假设系统应用发生问题,那么就是大家一起「死」,这其实也是单体系统最大弊端。

所以如果底层对接支付通道很多,像一般第三支付公司的支付系统,同一家银行的可能会对接很多支付通道,比对银联无跳转支付,网联支付,也有可能是 XX 行自己提供的接口。

那么这种情况就非常需要单独维护一个路由系统。

PS:630 政策之前,支付公司对接支付通道那真是一个多,同一家银行,可能会对接四五个通道。

但是 630政策之后, 不允许支付机构直接对接银行。

所以现在支付机构对接通道可能会比之前少很多。

路由系统实现方式有很多,下面主要分享一下我所经历过实现方案。

我们的路由系统经历过三个阶段的迭代,才有了现在的实现方案。

第一个阶段-混沌初开

这个阶段就跟上面讲的场景一样,业务需求较简单,仅仅只需要对接一两个支付通道。

为了快速上线,设计方案就简单粗暴,所有业务都处于一个应用。

支付子模块对内暴露暴露支付服务接口,由业务系统发起直接调用。

系统设计图如下:

100

这个阶段由于只有一个支付渠道,所以也不需要有路由系统,直接由业务系统调用支付服务接口发起支付。

不过随着业务量增大之后,这个设计方案就暴露很多问题:

  1. 业务系统与支付系统位于同一个系统,系统任何一次变更都会影响整个系统。
  2. 扩展性问题。每接入一个新的支付通道如微信,就需要增加一个新的实现类。另外,业务系统的代码同时也需要改动,需要调用新的实现类。

针对以上问题,我们进行第一版的改造。

首先我们将整个支付模块从原来应用中拆分出来,成为一个独立的子系统,专门运行支付业务。

这个系统对外提供一组支付接口,业务系统只需要调用这个接口,传入必要的参数,无需关心支付系统到底是如何实现的。

如果业务系统想指定某个支付通道,比如支付宝,那么可以在接口传入这个渠道标识,支付系统将会根据这个渠道标识调用相应的支付通道。

100

其次梳理渠道接口文档,抽象出共性接口,每个支付通道实现都需要继承这个接口。

0081Kckwly1gkgtcvt50lj31cs0u0wgx.jpg

这组通用渠道接口,其中 channelName 方法,代表这个实现类具体代表哪个通道。比如说这个方法返回 aliPay,那么就代表这个实现类将会调用支付宝通道。

支付系统子应用中将会维护一个类似路由表,这里简单使用 Map 存储映射关系,key 为上文提到的渠道唯一应用标识,而 value 为具体的实现类。

应用初始化之后,将会调用 Spring ApplicationContext getBeansOfType 方法,获取同一个接口的所有实现类 ,最后将其放入 Map 缓存中。

每次支付调用都会根据渠道唯一标识从路由表获取具体实现类,然后由具体的子类实现支付逻辑。

学过设计模式的同学,这里应该不会陌生,这其实是使用设计模式中的策略模式。

0081Kckwly1gkgse10bwij310j0u0kjj.jpg

这个阶段,由于业务还不是很复杂,系统还是挺简单,路由系统还只是系统中的一个子模块。

第二个阶段-神功初成

经历过一段时间,公司的业务量变的越来越大,这个阶段我们开始追求系统的稳定性。

但是在第一阶段设计方案中,支付系统所有模块位于同一工程。有些模块可能需要频繁发布,这样一旦发布就会影响所有系统功能。

第二点,系统功能全都耦合在一起,团队开发也变的困难,分支冲突,代码丢失也是经常的事。

第三点,一旦某些改动发布发生问题,整个系统都受到影响,真的是「要死一起死」。

所以这个阶段针对以上的问题,我们进行了相应改造,开始将支付系统进行拆分。

首先按照功能,将支付系统拆分几个独立的子系统,路由系统,渠道系统,成为独立系统,独立部署维护。

每个支付通道单独维护部署,成为一个单独的子应用。

100

系统之间的调用关系,就从同一进程内调用,变成使用 RPC 进行跨进程调用。

0081Kckwly1gkhm1a2sloj30p30c9aiv.jpg

这个时候就会有个问题,渠道系统可能会因为发布而下线/上线,这时路由系统必须动态维护这种关系,在渠道系统某一节点下线时,自动删除调用关系,而当应用上线时,新增调用关系。

说白了,路由系统需要实现渠道服务动态发现。

看到这里不要怕,其实 Dubbo 框架已经自带这个功能,我们没必要自己再去实现了。

Dubbo 配置中有一个属性-group,这个属性可以用于服务分组。

当同一个接口有多个实现,我们就可以根据这个来区分不同渠道系统的实现。

100

因为渠道系统实现同一组接口之后,提供出 Dubbo 服务需要加上相应的 group 属性,值为相应的渠道唯一标识。

如下所示:

100

路由系统只要引入这个 Dubbo 服务,设置相应的 group 属性 ,路由系统引用渠道系统的服务:

100

此时路由系统就跟第一阶段一样,内部维护一个路由表就好了。

这里采用了 XML 配置存储渠道标识与 Dubbo 引用服务的映射关系,如下所示:

0081Kckwly1gkhm8m39imj31760asdil.jpg

服务启动之后解析这个 XML 文件,然后将其维护在 Map 中。每次支付调用都会根据渠道唯一标识从路由表获取服务名,然后借助 Spring ApplicationContext#getBean 获取具体的 Dubbo 引用服务。

0081Kckwly1gkgse01ftmj31f10u0att.jpg

后续如果再新增渠道系统,路由系统不需要再修改任何代码,只要在配置文件中新增 Dubbo 服务引用以及增加路由表引用关系即可。

第三阶段-登峰造极

第二个阶段路由系统基本上已经满足现有阶段业务实用,不过还是存在个问题,渠道应用新增时,还需要新增配置重启应用

之前有一次新增渠道,忘记了在路由系统新增配置,从而导致新的渠道应用无法被调用,找了很久的问题,才发现是这个问题。

所以第三阶段,主要是优化路由系统,去掉上述配置文件,到达新增渠道应用,而不用重启路由系统。

这个阶段的改造,我们不再使用 XML 配置引用服务,而是借助 Dubbo API ,动态引用 Dubbo 服务。

查看 Dubbo 文档,可以直接使用 ReferenceConfig 直接查找服务提供者。

0081Kckwly1gkgse3orgwj31bh0u0b1a.jpg

官方文档建议:

ReferenceConfig 实例很重,封装了与注册中心的连接以及与提供者的连接,需要缓存。否则重复生成 ReferenceConfig 可能造成性能问题并且会有内存和连接泄漏。在 API 方式编程时,容易忽略此问题。

这里使用ReferenceConfigCache,用于缓存 ReferenceConfig 实例。

改造之后,去除之前所有引用服务配置文件以及缓存注册代码,不用再使用 Map 存储路由的映射关系。改造如下:

100

回顾上文,可以看到初期没有路由系统,整个系统可以运行下去。

但是随着业务量不断变大变复杂,最开始的系统架构已经不能适应当前的环境,所以我们才开始系统拆分,进行微服务改造,一步步改进系统。

改进的过程中,不断发现方案不足处,然后一步步迭代演进。这个过程中,要善于利用现有框架的功能,加速功能的开发。

最后,本文给出了几种不同阶段路由系统实现方式,适合不同阶段、不同类型的系统。

如果各位同学刚好也有类似需要,可以根据自己系统的情况借鉴参考。

好了,下周见~

0081Kckwly1gkhmhsrq1yg308c08cdq4.gif

本文首发于: https://studyidea.cn/pay-route

欢迎关注我的公众号:小黑十一点半,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn

006tNbRwly1gbkqdpfkutj30p00dwn0a.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK