我在之前公司的第一个任务就是开发一个统一的支付平台。由于公司业务需要,需要接入多个第三方支付。之前公司的支付都分散在各个项目中,不利于支付的管理,于是聚合三方支付,统一支付平台的任务就落在了我的手上。可以说设计是完全从0开始的,看了实战总结,对架构设计有了一些思考,之前一直想把自己的架构设计思路写出来,但是一直没有做它。前几天,有人在技术群里问了一个相关的问题。我觉得有必要写出来帮助别人。需要更多的开发者来开发支付平台。组件模式由于公司业务分布在多个地区,需要提供多种支付方式以满足业务发展,因此设计的支付平台需要接入多种第三方支付渠道,如:微信支付、支付宝payment,PayPal,IPayLinks等等,我们都知道每一个第三方支付都有自己的一套对外的API,以及官方的SDK来实现这些API。我们应该如何组织这些API?由于第三方支付渠道会随着业务的发展而变化,因此这些SDK的组织需要灵活、可插拔,同时不影响支付平台的整体架构。这里我使用组件的思想,将支付API拆分成各种组件:支付组件、退款组件、订单组件、Billing组件等,这样在引入第三方支付SDK时,可以将需要的API灵活地添加到组件中。架构设计如下:通过Builder模式,根据请求参数构建相应的组件对象,组件与外部隔离。隐藏组件构建的实现。组件模式+Builder模式,让支付平台具有高度的可扩展性。多账户系统对接各类第三方支付平台。我们当时遇到了另一个帐户问题。原因是当时公司的小程序和APP使用的是不同的微信账号,所以微信支付会对应多个账号。账户的问题,而我当时在设计支付平台的时候,并没有考虑到这个问题。当时第三方支付只对应一个账户,不同第三方支付的账户是独立的,不统一。所以我引入了多账户系统。多账户体系最重要的核心概念之一就是以账户为粒度,接入多个第三方支付,统一账户参数,构建统一的支付账户体系。支付平台不需要关心不同的支付。账户之间的差异以及是否有第三方支付有多少个账户。这时候我在支付平台架构图中加入了account层:前端只需要传入accountId,支付平台就可以根据accountId查询到对应的支付账户,然后构建对应的组件对象支付账户通过Builder模式,不同支付之间完全屏蔽在多账户系统中,可以支持多个支付账户,充分满足公司业务发展需求。统一回调异步分发处理做过支付开发的同学都知道,现在的第三方支付有一个特点,就是支付/退款成功后,会有一个支付/退款回调函数。目的是让商户平台自己检查订单是否合法,例如:防止客户端在支付时恶意篡改金额等参数。回调时,发现订单金额与验证时支付的金额不一致,将订单改为支付失败,防止资金损失。回调的思路是为了保证最终的一致性,所以我们在调用支付的时候,此时不需要校验参数的正确性,只需要在回调的时候校验即可。说完回调的目的,我们如何设计支付平台的回调呢?由于支付平台接入了多个第三方支付,如果此时每个第三方支付都设置了一个回调地址,那么就会有多个回调地址,因为必须暴露回调API才能接受第三方回调请求,所以会有安全问题。我们必须在API的外层设置安全过滤器,否则很容易出现一些非法的暴力访问,所以我们需要统一回调API。进行统一的安全检查,再进行一层分发。对于分发机制,我建议使用RocketMQ来处理。可能有人会问,如果使用RocketMQ进行分发处理,此时如何将校验结果实时返回给第三方支付呢?这个问题也是我当时头疼的问题。以下是我对回调设计的思考:公司系统基于SpringCloud微服务架构,微服务之间通过HTTP进行通信。当时我的支付平台接入了很多微服务。如果使用HTTP分发,可以保证消息返回的实时性,但是也会有一个问题。由于网络不稳定,会出现请求失败或超时的问题,无法保证接口的稳定性。如果第三方支付收到虚假响应,将在接下来的一段时间内再次发起回调请求。这样做的目的是保证回调的成功率。对于第三方支付来说,这还好,但是对于商户支付平台来说,这可能是一个比较坑爹的设计。大家想想,假设一个订单在支付的时候恶意篡改了金额,回调验证失败,给第三方支付返回了false。此时第三方支付会重复发送回调。无论发送多少回调,都会验证失败,增加了不必要的交互。当然这里也可以利用幂等性来进行处理。以下是微信支付回调的应用场景说明:基于以上两点考虑,我认为Falsetothird-partypayment是没有必要的。为了系统的健壮性,我使用消息队列进行异步分发。支付平台收到回调请求后直接返回true。这个时候,你可能会问一个问题。如果验证失败,但是此时返回true,会不会有什么问题?首先,如果验证失败,则订单必须处于支付失败状态。此时返回true的目的是为了减少与第三方支付不必要的远程交互。因为RocketMQ的消息是持久化到磁盘的,所以使用消息队列进行异步分发的好处是可以通过查看消息队列中的消息来排查问题,消息队列可以在业务高峰期进行流量调峰。下面是统一回调分发处理的架构设计图:聚合支付支付平台聚合了多种第三方支付,因此需要在请求层做大量的适配工作来满足各种支付的需求。你可能会想,直接在适配中加上几行ifelse。这样做没问题,也可以满足各种支付需求,但是你有没有想过如果这个时候加入第三方支付你会怎么做??只能在原有方法上加上多个else条件,这样会导致请求层代码随着业务的发展不断变化,代码极其不优雅,难以维护。这时候我们就不得不使用strategies模式,去掉这些ifelse代码,当我们添加第三方支付的时候,只需要新建一个Strategy类即可,strategy模式的使用方法可以看bigtalkdesign模式。因此,我在Builder模式之前额外增加了一个支付策略层:请求处理由于支付平台涉及资金,支付的各种请求和返回,以及异常记录在支付平台中是极其重要的,所以我们需要记录每一次支付请求记录以便后续故障排除。基于这个需求,我在开始请求第三方支付之前设计了一个Handler层。所有的请求都必须经过Handler层处理。Handler的核心方法如下:原则上,我设计的Handler层采用模板模式,不仅可以实现日志记录,还可以实现请求监听、消息推送等各种处理方式,实现Handler层的高可扩展性。下面是Handler层的架构设计图:上面写的***是我的支付平台架构设计思路。综上所述,支付平台需要具备可扩展性、稳定性和高可用性,所以我在设计支付平台的时候使用了很多设计模式以及消息队列的引入来处理回调分发问题,使得支付平台具备了这些特点.希望能给你一些启发和帮助。***我贴出支付平台的整体架构设计图:
