支付系统的设计

虽然之前的从业的公司一直和金融息息相关,也与多家支付或者银行系统进行过系统对接,但是支付系统一直没能从整体应用中真正独立

业务场景描述

混沌初开
1
2
3
4
5
6
7
graph LR
[业务流程1]-->[业务1]
[业务流程2]-->[业务2]
[业务流程3]-->[业务3]
[业务1]-->[支付]
[业务2]-->[支付]
[业务3]-->[支付]

在这个阶段,一般公司只会确认一家公司作为自己的第三方支付,而此时公司的技术人员架构还并不完整,很难找得到完全熟悉支付业务和支付系统的开发人员,在我接触过的第三方对接的系统里,大部分的基础类来自于支付公司的样例,这部分代码不能保障效率但是可以大大解决开发进度的问题,针对这部分代码也很难有人会维护

业务冲突
1
2
3
4
5
6
7
graph LR
[业务流程1]-->[业务1]
[业务流程2]-->[业务2]
[业务流程3]-->[业务3]
[业务1]-->[支付1]
[业务2]-->[支付1]
[业务3]-->[支付2]

经过一定时间的发展,因为支付公司提供的某个接口可用性不高,或者某种业务需求无法满足,可能会新引进一家支付公司,这个时候回针对部分业务进行替换

逐渐独立
1
2
3
4
5
6
7
8
9
10
graph LR
[业务流程1]-->[业务1]
[业务流程2]-->[业务2]
[业务流程3]-->[业务3]
[业务1]-->[支付代理]
[业务2]-->[支付代理]
[业务3]-->[支付代理]
[支付代理]-->[支付1]
[支付代理]-->[支付2]
[支付代理]-->[支付3]

随着第三方支付的增加和业务规则的不断变化,需要将业务模型进程抽象剥离,将交易过程进行委托代理,由代理进行实际的链接,简单介绍下这个调用链的各部分组成

  • 业务:业务模块只需要关心自己要执行的交易类型,以及业务所需要的支付方式
    • 该部分属于一个统称,业务选择支付方式的部分也可以进行封装,避免耦合
  • 支付代理:作为业务模块和支付模块的HTTP代理负责处理多对多模型下的网关路由,提供规范统一的API接口
    • 在提供统一API的时候,使用建造者模式是一个不错的选择
    • 不要试图通过任何方式来确定具体参数的合法性,只需要通过合适的机制比如token来确定请求的合法性即可
    • 尽量简化该步骤以增加吞吐量,并且把一切控制权交由支付系统处理
    • 作为一个网络代理,可以添加客户端负载均衡、熔断等策略来避免网络因素导致的资源不释放
  • 支付:作为第三方支付系统的真实对接系统,使用适配器模式将来自支付代理的统一API入参进行转换并进行实际处理,并将结果通过支付代理再次返回给业务系统,需要保证该服务的自治理,避免数据状态不同步造成的事故
    • 秘钥:基本采用第三方支付提供的非对称性加密方案
    • 渠道:这里的渠道代表着第三方支付对本公司系统的渠道标识
    • 接口:提供具体的业务模块,比如红包,退款
    • 同步通知:在双方的系统内进行一次HTTP链接,实时通知结果
    • 异步通知:在某些接口上需要跳转到第三方页面进行密码输入等操作,此时用户行为发生在浏览器中,第三方支付会使用异步通知的方式发送到一个指定的接口中
    • 其他通知:如果该交易发生在线下,第三方支付会将结果发送到协商的接口中,通知本公司系统该交易的发生
    • 幂等性:针对同一笔交易有且仅有一个结果,
    • 自治理:自治理分为两部分,一部分是对第三方支付,需要保证长时间未明确结果的交易和第三方支付状态同步,另一部分是对业务系统,在返回结果时未收到响应应该及时切断链接避免木桶效应,并使用延时队列等方式再次发送结果,避免上游系统崩溃导致的系统性能占用
API变化问题

第三方支付系统的API升级不可控,在生产环境中进行版本升级需要在编码中添加参数并进行灰度发布,为了保证7*24小时服务,不可能频繁进行发布,此时应该动态获取参数

业务支付配置表

  • 规则ID
  • 业务ID
  • 支付系统ID

第三方支付配置表

  • 支付系统ID
  • 请求方式
  • 秘钥规则ID

第三方支付秘钥表

  • 秘钥规则ID
  • 加密方式
  • 公钥
  • 私钥

第三方支付参数表

  • 参数表ID
  • 支付系统ID
  • 功能接口ID
  • 商户号
  • 版本号
  • 同步地址
  • 异步地址

第三方支付个性化参数表

  • 参数表ID
  • 参数名
  • 默认值

把具体对接时的参数以表的形式存储,提供合适的缓存机制,保证效率,以及更新的速度