收益发放资金回流链路系统的开发

一.开发背景

在项目成功后会有个收益发放的流程,把校验好的总金额核算无误后,批量打款给用户的流程。因为整体流程比较长,用文档记录下来整个过程

二.链路介绍

1.sftp账单明细核对系统

(1)sftp业务流程图
这里写图片描述
(2)sftp技术流程图
这里写图片描述
(3)定时任务体系:
定时任务a:扫描正在执行中的项目,计算生成订单文件后并上传tfs,并且在数据库中记录下该文件信息
定时任务b:将信托公司上传收益明细的文件上传tfs上,并且在数据库中记录下该文件信息
定时任务c:定期根据数据库里的订单文件和收益明细文件记录定时同步tfs上的文件到本地
定时任务d:将信托公司上传的他们的收益明细和我们的订单数据进行核对

2.sftp上传下载

a.申请了办公网VIP以及对应外网VIP的ACL变更,将部分外网的IP加入IP白名单,这样可以让外网的信托公司能访问VIP转发的单机。(VIP是虚拟IP,通过负载均衡的方式转发请求到绑定的服务器,相当于分配给内网机器全球IP)
b.在服务器集群的这台被“选中”的单机上创建信托公司的SFTP账户,账号密码我们提供,账户的密码要符合集团安全规范:密码12位,包含数字,字母,特殊字符。信托公司可以使用这个SFTP账户在相应的自己公司的目录上上传自己的收益明细文件,下载我们生成与他们合作项目的订单明细。
c.使用chroot 使信托公司的根目录在指定文件下,对他们访问的路径进行权限控制。这样能维护我们服务器系统上的安全与信息保密。
d.给每台机器都设置好SFTP账户,但是VIP仍然指向单机(不指向集群,是因为没有必要,这台单机主要是作为能让信托公司上传收益明细的跳板,上传的文件能被定时任务c同步到其他服务器。指向了集群会出现信托公司上传的文件不知道会到哪一台服务器,于是本来指向单台时只有指向的服务器需要开启定时任务b,现在所有服务器都要开启定时任务b,浪费了机器资源)。这样可以在VIP指向的这台单机挂了的同时可以立刻转移指向的目标到其他机器,以此提高我们SFTP服务的可用性。

三.来账消息

1.信托公司打款给支付宝备户金账户,发出来账通知,并处理该通知

a.提供支付宝可以发送通知的URL(HttpServlet轻量实现,利用其它框架也可),在支付宝发来消息后对所有的参数进行日志记录,然后校验合法性。
这里写图片描述
b.对收到的参数利用非对称加密算法DSA对报文里的内容进行验签,用于验证消息是支付宝方发送。
这里写图片描述
c.将每一笔验证成功的通知进行落库,并记录下版本号。如果成功要返回SUCCESS通知支付宝的Notify消息不用重试。关于来账通知密等性的保证,是从库里捞出所有来账通知相同订单号的最后一条作为要参与处理的通知(因为该来账通知是全量不是增量,最后一条相同订单号的通知就是终态)。落库失败就日志记录,并且响应支付宝再发一条重新尝试落库。
这里写图片描述

四.受托支付

1.资金回流技术流程图

这里写图片描述

2.资金回流业务流程图

这里写图片描述

3.发起用户收益发放打款,创建受托主订单

a.关于发起打款流程,由于PD的预期是可以控制打款的触发,而非代码的自动调用,于是没有使用定时任务,或者代码的流程调用。
b.对来账通知的内容进行了一系列的校验,看是否符合打款要求。
c.创建受托主订单调用接口 alipay.fund.stdtrustee.masterorder.create
d.写了groovy脚本触发整个流程,用它是因为它是脚本语言不用编译,curl一把就能调用整个流程。

4.从备付金账户打款到支付宝内部户,资金搬运

a.发起受托主订单搬运资金,并获得受托主订单号alipay.fund.stdtrustee.order.pay

5.从支付宝内部户批量打款给用户

a.批量去库里捞已投资用户,用了分页捞库的方式,500条数据一拉(怕数据量一拉过大会严重施加数据库IO压力,以及短时间内用List引用的这些对象内存占用过多,一不小心就FULL GC 频繁,然后最坏可能OOM)
b.采用了线程池处理任务,利用服务器多核的运算能力,通过加速批量打款给用户的任务。同时考虑线程创建过于频繁时,可以使用线程池来复用闲置线程来节约创建,销毁线程的开销,并能对线程数进行合理的管理,避免线程过多耗尽系统资源。
这里写图片描述
这里写图片描述
c.使用了Future编程,进行解耦,不再一个批量创建受托子订单打款给用户的循环里加过多逻辑,这样使得代码更清晰易懂,便于维护。这样也同时使得创建受托子订单的等待时间去除:并使得原本需要等待每笔订单是返回了状态之后再处理数据,变成了可以发送请求创建订单,另一边可以同时异步的处理这些订单已返回来的状态,加快了打款任务的处理。
这里写图片描述
d.引用了消息机制:
(1)在用户打款成功时,发送MetaQ消息,情况缓存用户财富的Tair,触发更新用户展示当前财富的逻辑。
这里写图片描述
(2)当出现调用接口系统异常时或者资源限流时,使用Nofity消息进行触发重试打款的逻辑。用Notify消息中间件的一点重要原因是它有非常符合应用场景:就是当发送消息失败时会进行阶段递增的重试机制。如果业务逻辑对消息中间件返回了false的消息,那么就会进行重试,而且重试间隔越来越长。maxRetry属性可以设置重试次数。
这里写图片描述
e.对于每笔订单的打款状态进行落库,以便于统计出打款的所有状态,方便以后查询打款情况和重试失败订单。
这里写图片描述

6.对于打款给用户失败的情况进行补救处理

a.与批量打款给用户的流程类似,不过是通过从DB里捞未成功的订单然后进行批量重试,然后更新订单状态(不新建是因为没必要,业务只关心是否打款成功,如果失败要知道失败的原因。至于打款了几次是无所谓的)。
b.又是是一个groovy脚本来触发订单补救流程

五.整体流程需要注意的地方

1.异常的处理

要十分注重这种长流程系统异常的捕捉,因为中途随便一个什么运行时异常都能让线程退出执行,让后续的代码不work。
(1)对于受托主订单,和资金搬运到内部户的受托子订单,我是选择了有异常直接退出资金回流的流程。因为它们是流程的主干,没有流程根本没有执行下去的必要。
这里写图片描述
(2)对于批量打款给用户的受托子订单打款时如果出现了异常,那么日志记录,并落库记录就好。因为批量打款给用户的过程本身就应该是相互独立,互补影响的。
这里写图片描述

2.对代码健壮性的较高要求

毕竟和上千万打交道的代码,不够健壮是种对业务毁灭性的打击。关键是校验入参出参,判断好每一步可能出现不预期的情况该怎么处理,然后在关键的地方记录下日志便于日后排查问题。

六.总结

首先,作为一个应届生还是很高兴自己能独立开发一个这么重要的资金回流的链路(毕竟和千万以上的资金打交道,成功了会有成就感,失败了就GG)。在开发过程中,一直在想着怎么优化健全我这套系统的代码,要感谢我寻求帮助时给我指导的师兄。
然后感谢联调时支付宝同学给我的帮助,一次次陪我把整个链路跑通,尤其是在他们本身任务很多,繁忙的情况下(双十一,双十二的夹击)。

猜你喜欢

转载自blog.csdn.net/qq_16681169/article/details/53577042