高性能低成本对账解决方案

对账的相关业务知识和常用的算法可参考:如何做一个对账系统
这里我们直接上干货,介绍高性能低成本对账的核心算法。先说结论,经该算法改造的对账系统可以在 一分钟 内完成 一两千万 规模的支付流水对账(改造前需要约 2 小时),而且无需为此增加任何硬件资源。

方案流程

  1. 日切后将我方的 T日 交易记录从数据库中按渠道导出成文件,并按交易流水号 排序
  2. 从上游渠道(银行、银联等金融机构)获取对账文件,对文件按交易流水号 排序 并保存;
  3. 对我方支付订单文件与渠道对账文件在程序中进行单向遍历逐一 对比 查找出差异记录。

核心过程

这个方案中,核心过程就是 排序 和 对比,这里详细介绍一下这两个过程的实现方式。

排序

不管是我方支付订单文件还是渠道侧的对账文件,都需要按照我方的交易流水号进行排序。具体的排序过程可以通过程序实现的方式利用各种排序算法来完成。当然,如果想更省事一些,可以直接使用 Linux 的 sort 命令(内部是用归并排序算法实现的)对文件按指定栏位进行排序。

对比

在双方文件都排序后,对两个文件进行 单向遍历 并逐项对比,在此过程中可以找出差错项并处理。这个对比过程效率非常高,主要就在于对文件行的读取只需前向滚动,不需要做回退或者查找动作。

对比过程的伪代码如下:

/**
* order_sorted:表示排序后的支付订单文件
* channel_sorted:表示排序后的渠道侧对账文件
*/
function compare(file order_sorted, file channel_sorted)
    order_line = readLine(order_sorted)
    channel_line = readLine(channel_sorted)
    while not eof(order_sorted) and not eof(channel_sorted)
        order_id = getId(order_line)
        channel_id = getId(channel_line)
        if order_id = channel_id // 流水号匹配上了,仍需要看业务内容是否一致
          find difference between order_line and channel_line
          order_line = readLine(order_sorted)
          channel_line = readLine(channel_sorted)
        else if order_id < channel_id // 出现短款
           handle_cash_short  for order_line
           order_line = readLine(order_sorted)
        else // order_id > channel_id  出现长款
           handle_cash_over for channel_line
           channel_line = readLine(channel_sorted)

    if not eof(order_sorted) // 支付订单文件仍有部分行未读取,剩余的全部视作短款
        handle_cash_short for the remanent of order_sorted 
    if not eof(channel_sorted) // 渠道侧对账文件仍有部分行未读取,剩余的全部视作长款
        handle_cash_over for the remanent of channel_sorted 

方案分析

  • 算法时间复杂度
    在上述解决方案的两个核心步骤中,文件排序一般来说采用高效的排序算法,大致可以做到 O(n*logn) 的时间复杂度;文件对比因为是单向遍历,可以做到 O(n) 的时间复杂度。从具体业务场景来看,真正的对比过程发生在渠道侧文件来到之后,因此我方支付订单文件可以提前导出并排序,实际上不占用对账处理时间。
  • 算法空间复杂度
    排序步骤如使用合适的算法(如归并排序)其内存的使用是固定的,比如使用 sort 命令可以指定使用的内存大小或总内存占比,因此是 O(1) 的复杂度;对比步骤使用文件行读 API 也是可以指定 buffer 大小的,因此也是 O(1) 的复杂度。
    总之,这两个步骤都不会因为文件太大而出现内存不足的情况。

从最终的落地情况来看,该方案整体性能高,内存使用量固定,而实现复杂度却比较低,不需要借助第三方系统(如 redis、nosql库等)即可完成。

进一步优化方向

  1. 提高排序和对比过程的并行度
    具体实现中,文件排序 和 文件对比步骤我们仍然采用的是单线程的处理方式。如果机器的 CPU 核数够多的话,也可以对这些步骤进行并行处理。简单来说,sort 命令有指定并行度的选项;文件也可以划分成 chunk,分 chunk 来进行并行对比。
  2. 超大规模对账过程
    实际上,该算法也可使用 MapReduce 框架来实现。但在文件小于 5G 的情况下并不推荐,因为这个规模的文件在 Hadoop 上的网络传输开销也要几十秒的时间了。其实对于 GB 级规模的文件,单机处理效率比 Hadoop 集群可能还要高,有兴趣的话可以看看 这篇文章

posted on 2020-08-06 15:34  bugcai  阅读(520)  评论(0编辑  收藏  举报

导航