最新消息:

支付系统对账算法优化方案

互联网金融 admin 3797浏览 1评论

一、目前对账的算法:

1、从上游渠道(银行、银联等金融机构)获取对账文件,程序逐行解析入库

2、在存储过程中,以上游对账文件的表为基准,程序逐行读取并与我们系统的交易记录/账务记录(有账务系统情况下,合理方案应该是于账务记录)对比,查找出差异记录。

3、以我们系统的交易记录/账务记录为基准,程序逐行读取与上游对账文件对比,查找出差异记录

 

二、目前对账算法问题:

1、使用存储过程,对账过程都在数据库端完成,对数据库性能影响较大,而且对账逻辑扩展极为麻烦

2、逐行比对算法效率较低,但算法上并无好的优化余地。如果采用数据库INTERSECT、MINUS对数据库压力也高。

3、在业务量大的情况下(例如有上百家上游渠道需要对,每一家都有几十万条交易记录),对账服务器及数据库服务器负荷较高。即便采用读写分离,对账时候使用读库,压力一样很大。

4、导入批量文件,逐行入库效率较为低下(每一次都需要建立网络连接、关闭连接)

 

三、对账算法优化思路:

1、涉及网络传输的,尽量采用批量方式操作,减少网络消耗及时间消耗

2、使用Redis等NOSQL数据库,降低数据库服务器的压力。同时在扩展上也容易,一台Redis服务器不够,可以无限制增加用于对账用的服务器。

3、使用Redis的set集合的sdiff功能,利用Redis sdiff算法的高性能,比对上游记录和我方记录的差异

 

四、对账算法说明:

1、利用Oracle/Mysql的load data infile将对账文件批量导入到数据库

2、程序读取上游账务记录表,对上游账户记录执行select  concat(channel_id, ":" , order_id , ":" , HASH_MD5(channel_id , order_id , amount , status , timestamp1 , timestamp2 ,…) )  as hashid from table ,得到对应的SET集合。

这里思路是将需要对账的记录拼成格式为:channel_id:order_id:hashid形式的串,以便作为Redis SET集合的item。

其中channel_id和order_id用于标识对应的渠道及订单,只是例子,根据实际需要补充。之所以要在hashid前面带上channel_id和order_id,主要目的是在sdiff后,能够作为主键,根据set结合的item查找出对应的数据库记录。

3、对我方的交易记录表/账户历史表采用上一步的类似算法,得到对应的SET结合

4、采用Redis的pipeline功能(Redis的各种客户端,包括java客户端jedis 都提供此功能),将上游账务记录SET集合和我方的交易记录/账务历史记录SET集分别批量执行sadd插入Redis,得到两个SET集合。

由于单条记录sadd 插入Redis效率较差(每一次都涉及网络open、close、传输消耗),因此使用Redis的pipeline功能,已实现批量入库功能。

可以参考:http://redis.io/topics/mass-insert

5、利用redis的sdiff功能查找出上游账务集合与我方记录集合的差值

6、从sdiff 集合中channel_id:order_id:hash,定位对应的数据库记录,更新对账状态。

具体性能及实现可以在实现后测试对比一下,应该会有大幅的性能提升。

转载请注明:出家如初,成佛有余 » 支付系统对账算法优化方案

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

  1. 好方法! 约定数据格式,省去数据批量入库过程,将数据全堆到内存:channel_id:order_id:hash, 排序2 * O(N*log(N)), 做集合差O (M * N) 。 放不下内存,就做文件排序。
    zhoujiagen9年前 (2015-07-14)回复