支付网关系统优化

POS前置系统

系统现状

  1. |-------------|
  2. | 负载均衡 |
  3. |-------------|
  4. |------|
  5. | 应用 |
  6. |------|

系统并发瓶颈

  • ServerSocket单线程接收数据 -》 netty
  • http调用第三方服务操作 -》改为异步http工具
  • 日志同步IO操作 -》 改为log4j异步日志
  • 轮询情况下sleep阻塞线程 -》改为协程,异步,或通知回调等方式轮询
  • 数据库JDBC同步IO操作 -》暂不改动,考虑目前数据库响应速度较快

并发优化

高并发方案

Reactor异步方案

Vert.X + RxJava

spring-boot 2 reactive + ProjectReactive

协程方案

netty + quasar携程库

网关系统2.0方案

  • 因决定要实现POS机的一机一密,系统会有大改动,趁此机会,可以重构网关系统的2.0版本

需求

  • 高并发,高可靠性
  • 保证之前版本的兼容性
  • 最好http与tcp接口,保持相同的项目。

方案

方案一
  • 一个tcp网关,解析8583报文,老版本直接透明转发(如果签名方式变化,可能需要重签名),新版本解析报文后并进行一些验证处理后,请求后端rest服务,轮询,关单等逻辑在网关实现。
  • 一个http网关,进行验签,转发等操作。
  • 后端采用微服务等模式,提供restful接口。
  • 数据库维持不变

方案二

支付网关系统

数据库方面优化

交易系统

  1. 对于不经常变化并且可以接收一定时间的数据不一致状态的数据,如用户基本信息,用户支付信息,用户费率信息,支付产品配置,支付渠道配置等,使用缓存保存(redis),所有数据都从缓存中读取,减轻对数据库压力。
  2. 对于经常变化的数据,如订单信息,其特点为订单创建的很短一段时间内会被频繁的访问,可以在订单创建时分别缓存其商户号+商户订单号(key)-》主键ID(value),平台订单号(key)-》主键ID,银行订单号(key)-》主键ID(value),主键ID(key)-》订单数据(value),时间为3分钟(订单被创建支付成功并通知商户后,很少会被再访问)。不过要注意所有修改数据库订单时,需同步更新主键ID-》订单数据的缓存。

管理系统

  1. 管理系统一般会使用复杂的查询语句,并且查询的数据跨度很大,难以通过缓存进行优化,可通过数据库读写分离机制,将管理系统的读请求,分发到从库中,减少复杂查询对主库的压力。读写分离可通过数据库中间件(如mycat)或者mybatis插件来完成,他们对应用都是透明的。

IO优化

对服务请求的IO优化

  • 目前向渠道请求,一般需要一秒以上才会收到响应,这段时间,线程一直在等待,造成极大的性能浪费。

对商户端的IO优化

  • 商户发送同步请求,会占用线程,造成性能浪费。

账户表锁竞争优化

  • 目前,每笔交易完成后,会同步向商户及代理商的账户中加账户余额,因此所有代理商下的订单都会需要获取代理商账户表的锁,当并发稍大(仅单代理商十几线程时),会出现长期获得不了锁,造成线程等待,无法返回商户数据的问题。

解决方案

  1. T1交易,商户对账户余额实时性要求不高,并且余额数据仅作为虚拟账户做参考,清算需对账完成后才会发起,可以对账户余额同步处理转异步处理,可以优化商户调用api的体验。当支付成功后,发送消息到mq,消费者获得消息,异步处理账户余额及分润信息。
  2. 异步处理,只能起到不影响交易,和削峰值的作用,当长期高并发时,消费者来不及处理mq消息,会造成消息堆积,甚至会使mq无法承受。
  3. 资源竞争问题,1是增加资源,2是减少竞争者,因为账户为一条记录,难以增加资源,但是可以通过合并账户操作,来减少竞争。例如,可以每一百条账户操作记录,起一个事务,将需要变化的总金额通过应用计算后,一次增加账户余额中,可以极大的减杀竞争,或者使用定时器,没隔一段时间,将成功的交易余额一次加到账户余额中。