很早 之前写过一篇支付对账相关文章,那时候负责对账系统日均处理数量比较小。
那最近正在接手现在的对账系统,由于当前系统日均数量都在千万级,所以对账系统架构与之前架构完全不一样。
那就这个话题,聊聊如何实现千万级数据支付的对账系统。
我们先来回顾下什么是对账?
也许你对对账这个概念比较模糊,但是这个场景你肯定碰到过。
上班路上买了一个煎饼,加了根里脊与王中王,然后你扫了老板的二维码付了 10 元钱。
你跟老板说你已经付了 10 元钱,老板看了下手机,果然有一条 10 元支付记录,老板确认收到钱,然后就把煎饼给你。
这个过程,你说你付了 10 元,老板确认收到 10 元,这就是一只简单的对账过程。
回到我们支付场景,用户下单使用微信支付 100 元购买了一个狗头抱枕,这时我们这边会生成一条支付记录,同时微信支付也会生成记录。
那微信第二天就会生成一个账单记录,我们拿到之后把我们的交易记录跟微信记录逐笔核对,这就是支付对账。
正常支付的情况下,两边(我们/第三方支付渠道)都会产生交易数据,那支付对账过程,两边数据一致,大家各自安好,不用处理什么。
但是有些异常情况下,可能由于网络问题,导致两边数据存在不一致的情况,支付对账就可以主动发现这些交易。
对账可以说支付系统最后一道安全防线,通过对账我们可及时的对之前支付进行纠错,避免订单差错越积越多,最后财务盘点变成一笔糊涂账。
开篇先来一张图,先来看下整体对账系统架构图:
整个对账系统分为两个模块
对账模块,主要负责对账文件拉取,数据解析,数据核对,数据汇总等任务。
差错模块是对账模块后置任务,对账模块核对过程产生无法核对成功的数据,这类数据件将会推送给差错系统。
差错系统将会根据规则生成差错订单,运营人员可以在后台处理这列数据。
今天这篇文章先不聊具体的系统设计,先来回顾下之前的对账系统设计,简单了解下对账的整体流程。
对账系统如果从流程上来讲,其实非常简单,引用一下之前文章流程图:
https://studyidea.cn/articles/2019/08/26/1566790305561.html
整体流程可以简单分为三个模块:
本端数据指的是我们应用产生的支付记录,这里根据账期(交易日期)与渠道编号获取单一渠道的所有支付记录。
对端数据指的是第三方支付渠道支付记录,一般通过下载对账文件获取。
由于每个渠道下载方式,文件格式都不太一样,对端数据处理的时候需要将其转化统一数据格式,标准化在入库存储。
网上找了一份通用账单,可以参考:
对端数据转化存储之后,对账流程中,对端数据也需要跟本端数据一样,获取当前账期下所有记录。
两端数据都获取成功之后,接下来就是本地数据逐笔核对。
核对流程可以参考之前写的流程:
上面流程其实也比较简单,翻译一下:
查找本端数据/对端数据,然后转化存储到 Map 中,其中 key 为订单号,value 为本端/对端订单对象。
然后遍历本端数据 Map 对象,依次去对端数据 Map查找。如果能查找到,说明对端数据也有这笔。这笔核对成功,对端数据集中移除这笔。
如果查找不到,说明这笔数据为差异数据,它在本端存在,对端不存在 ,将其移动到差异数据集中。
最后,本端数据遍历结束,如果对端数据集还存在数据,那就证明这些数据也是差异数据,他们在对端存在,本端不存在 ,将其也移动到差异数据集中。
PS:上述流程存在瑕疵,只能核对出两边订单互有缺失的流程 ,但是实际情况下还会碰到两边订单都存在,但是订单金额却不一样的差异数据。这种情况有可能发现在系统 Bug,比如渠道端上送金额单位为元,但是实际上送金额单位为分,这就导致对账两端金额不一致。
之前对账系统日均处理的支付数据峰值在几十万,所以上面的流程没什么问题,还可以抗住,正常处理。
但是目前的支付数据日均在千万级,如果还是用这种方式对账,当前系统可能会直接崩了。。。
第一个,查询效率。
本端/对端数据通过分页查询业务数据表获取当天所有的数据。随着每天支付数据累计,业务表中数据将会越来越多,这就会导致数据查询变慢。
实际过程我们发现,单个渠道数据量很大的情况下,对账完成需要一两个小时。
虽然说对账是一个离线流程,允许对账完成时间可以久一点。但是对账流程是后续其他任务的前置流程,整个对账流程还是需要在中午之前完成,这样运营同学就可以在下午处理。
第二个问题,OOM。
上面流程中,我们把把全部数据加载到内存中,小数据量下没什么问题。
但是在千万级数据情况下,数据都加载到内存中,并且还是加载了两份数据(本端、对端),这就很容易吃完整个应用内存,从而导致 Full GC,甚至还有可能导致应用 OOM。
而且这还会导致级联反应,一个任务引发 Full GC,导致其他渠道对账收到影响。
第三个问题,性能问题。
原先系统设计上,单一渠道对账处理流程只能在单个机器上处理,无法并行处理。
这就导致系统设计伸缩性很差,服务器资源也被大量的浪费。
上面系统代码,实际上还是存在优化空间,可以利用单机多线程并行处理,但是大数据下其实带来效果不是很好。
那主要原因是因为发生在系统架构上,当前系统使用底层使用 MySQL 处理的。
传统的 MySQL 是 OLTP (on-line transaction processing),这个结构决定它适合用于高并发,小事务 业务数据处理。
但是对账业务特性动辄就是百万级,千万级数据,数据量处理非常大。但是对账数据处理大多是一次性,不会频繁更新。
上面业务特性决定了,MySQL 这种 OLTP 系统不太适合大数据级对账业务。
那专业的事应该交给专业的人去做,对账业务也一样,这种大数据级业务比较适合由 Hive、Spark SQL 等 OLAP去做。
今天本篇文章只是一个序曲,主要聊聊对账业务基本流程,聊聊之前系统架构在大数据下存在的问题。
后面文章再会介绍下大数据下对账系统如何设计,对账之后差错数据如何处理,尽请期待。