当前位置:首页 > > 架构师社区
[导读]提到路由,不免会想到网络通信过程中起到数据包转发的路由器。而我们今天讲到支付路由系统,也是起到类似的作用。

支付路由系统

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

从无到有,支付路由系统升级打怪之路(原创)
图片来自网络

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

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

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

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

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

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

为什么需要路由系统

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

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

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

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

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

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

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

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

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

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

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

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

实现方式

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

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

第一个阶段-混沌初开

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

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

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

系统设计图如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

第二个阶段-神功初成

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

如下所示:

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

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

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

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

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

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

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

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

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

第三阶段-登峰造极

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

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

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

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

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

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

官方文档建议:

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

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

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

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

总结

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

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

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

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

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

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

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

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

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

长按订阅更多精彩▼

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

如有收获,点个在看,诚挚感谢

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭