有赞业务对账平台的探索与实践

2020 年 3 月 15 日

有赞业务对账平台的探索与实践

一、引子


根据 CAP 原理,分布式系统无法在保证了可用性(Availability)和分区容忍性(Partition)之后,继续保证一致性(Consistency)。我们认为,只要存在网络调用,就会存在调用失败的可能,系统之间必然存在着长或短的不一致状态。在服务化流行的今天,怎样及时发现系统服务间的不一致状态,以及怎样去量化衡量一个系统的数据一致性,成为每个分布式环境下的开发者需要考虑并解决的问题。


二、背景


以交易链路为例,存在着如下一些潜在的不一致场景:


  • 订单支付成功了,但是订单状态却还是“待付款”

  • 物流已经发货了,但是订单上面还是“待发货”

  • 银行退款已经到账了,但是订单上面还是“退款中”

  • 订单发货已经超过7天了,但是却没有自动完成


上述每个业务场景,都可能产生用户反馈,给用户带来困扰。业务对账平台的核心目的,就是及时发现类似问题,并及时修复。使问题在反馈前即被提前处理。


三、挑战


那么一个业务对账平台,会面临着哪些挑战?



我们对于一个业务对账平台的核心诉求,主要包括要方便业务系统快速接入,要能处理业务方海量的数据,并保证一定的实时性。这会深刻影响业务对账平台的系统设计。


四、架构


从局部到整体,本文先从解决上面三个问题的角度,来看有赞业务对账平台的局部设计,再来看整体系统结构。


4.1 易于接入


我们认为所有的对账流程,都可以分解为“数据加载”、“转换解析”、“对比”、“结果处理”这 4 步。为了适应多样化的业务场景,其中的每一步都需要做到可编排,放置各种差异化的执行组件。在每一个流程节点,需要通过规则可以自由选择嵌入哪个组件。其次,需要把数据从原始格式,转换到对账的标准格式(基于标准格式,就能做标准的通用对比器)。总结起来,我们认为对账引擎需要具备以下的能力:


  • 流程编排能力

  • 规则能力

  • 插件化接入能力


目前业务对账平台的对账引擎结构如下:



其中的 ResourceLoader 、 Parser 、 Checker 、 ResultHandler 均为标准接口,所有实现了对应接口的 spring bean,都能被编排到对账流程之中,包括业务方自己实现的 plugin。这样就实现了插件化和可编排。每个流程节点的功能如下:


  • ResourceLoader :基于各种数据源(DB、FILE、RPC、REST 等)提供加载器工厂,加载各个数据源的原始数据。加载的方式支持驱动加载、并行加载、多方加载等方式。业务方也可以自己实现加载器,利用流程编排能力嵌入到对账流程中。

  • Parser :对已加载的原始数据进行建模,转换为对账标准模型。利用规则引擎,提供脚本化(Groovy)的转换方式。

  • Checker :按照配置对指定字段、按指定规则进行比较,并产生对账结果。支持findFirst(找出第一个不一致)、full(找出所有不一致)等对比策略。

  • ResultHandler :使用指定的 handler 对结果进行处理,常见的处理器包括持久化、发送报警邮件、甚至直接修复数据等等。


通过统一的 facade,将整个对账流程进行串联。在执行不同节点时,根据配置选择不同的默认组件或者插件来执行。可以在管理后台,对每个流程节点进行编排:



4.2 高吞吐量


一些离线定时对账场景,单次对账的数据量可能达到百万级,甚至千万级。这对对账平台的吞吐量造成了挑战。我们面对海量数据问题的通常解决思路,就是“拆”。分布式任务拆分+单机内任务拆分,将数据块变小。同时,也可以利用一些大数据的工具来帮我们减轻负担。



目前的对账有 2 种模式:一种常规模式,是通过数据平台(包含了所有要进行对账的原始主键数据,如订单号)将数据 push 到对账中心的 DB,然后订单中心集群通过分片策略,并按分页分批加载,加载数据进行对比。另一种,则是当数据量超过千万时,利用数据平台的 spark 引擎从 hive 表中获取数据,然后投递到 nsq(自研消息队列)。nsq 会选择其中一个 consumer 进行投递(不会投递到多个 consumer)。这样千万级的数据会变成消息被分散的对账服务器执行。


对账任务一般会选择在业务量较小的凌晨进行,是因为在对账过程中会需要通过反查业务接口,来获取实时数据。而更好的情况是,对账时能去除对业务接口的反查。因此,会需要对业务数据进行准实时同步,提前进入对账中心的 DB 集群。



主要思路是基于业务 DB 的 binlog 日志或者业务系统自身的消息,进行数据同步。后续流程则类似。


4.3 高实时性


一些特定的业务场景,比如买家已经付款成功了,但是由于银行第三方的支付状态回调延迟,导致订单状态还是待付款。这种情况,买家会比较焦急,可能产生投诉。面对这样一些场景,就需要进行实时对账,也可以叫做秒级对账。


秒级对账往往基于业务消息进行触发,需要在事件触发后的短时间内执行完对账任务。且事件消息的触发,往往具有高并发的特点,因此需要相应的架构来进行支持。



设计中主要加入了 EventPool 来缓冲处理高并发的事件消息,并加入限流、取样、路由、处理的 pipeline。同时在进入事件处理线程池之前,需要进入阻塞队列,避免大量的请求直接耗尽线程资源,同时实现事件处理的异步化。处理线程批量定时从阻塞队列获取任务来执行。同时,利用延迟阻塞队列,还可以实现延迟对账的特性。(我们认为出现不一致的情况时,如果立即去进行对比,往往还是不一致的。所以就需要根据情况,在事件发生后的一段时间内,再触发对比)


4.4 整体设计


上面介绍了业务对账平台的各个局部设计,下面来看下整体结构。



整体上主要采用调度层+对账引擎(core+plugin)+基础设施的分层架构。调度层主要负责任务触发、任务拆分、调度;对账引擎则负责执行可编排的对账流程;基础设置层则提供规则引擎、流程引擎、泛化调用、监控等基础能力。


五、健康度


对账中心可以拿到业务系统及其所在整个链路的数据一致性信息。基于此,对账平台具备了给予业务系统和链路健康度反馈的能力。



六、共建


前面有提到,对账的流程被拆分为四个固定的流程节点,且有四个对应的标准接口。通过流程引擎和规则引擎的能力,可以根据 spring bean name,来将系统默认组件或者插件编排到对账流程之中。基于这种开放性的设计,业务对账平台支持与业务团队进行共建。


首先,对账平台提供标准接口的 API jar 包,业务方通过引入 jar,实现相关接口,并将 impl 打包。这样,对账平台通过 spi 的方式,可以引入业务方的插件包,并加载到对账中心的 JVM 中执行。


七、未来


业务对账平台,是面向业务场景建立,但同时属于数据密集型应用。平台上线以来,已经接入公司各团队数十个对账任务,每天处理千万级的数据。展望未来,业务对账平台的使命会从主要进行离线数据分析处理,演进到利用应用系统的健康度数据帮助系统进行实时调整的方向。在分布式环境下,没有人能回避数据一致性问题,我们对此充满着敬畏。欢迎联系 zhangchaoyue@youzan.com,交流心得。


2020 年 3 月 15 日 20:18296

评论

发布
暂无评论
发现更多内容

深度剖析原理!2020年Android网络编程总结篇,已开源

欢喜学安卓

android 程序员 面试 移动开发

【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

herongwei

c++ 后端 迭代器模式 源码剖析 stl

Android知识体系大纲!Android平台HTTPS抓包解决方案及问题分析,年薪50W

欢喜学安卓

android 程序员 面试 移动开发

我们该如何正确的中断一个线程的执行??

冰河

Java 并发编程 多线程 高并发 中断线程

架构师训练营第十一周作业

文智

极客大学架构师训练营

Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)

刘悦的技术博客

django Vue 微信支付 python3 请求数据 扫码

文件写入的6种方法,这种方法性能最好

王磊

Java io 文件读写 文件操作 文件写入

不讲码德!坏味道偷袭我这个老码农

爱笑的架构师

Java 代码审查 代码坏味道 代码规范 七日更

甲方日常 71

句子

工作 随笔杂谈 日常

突破某度云盘下载限速,提速30倍!想学?我教你啊

Silently9527

百度云 HTTP

数字货币量化交易所系统开发案例

系统开发咨询:I76-883I-5I52 邓森

【Java入门】String,StringBuffer和StringBuilder

HQ数字卡

Java 七日更

阿里P8手把手教你!微信小程序的事件处理,安卓系列学习进阶视频

欢喜学安卓

android 程序员 面试 移动开发

TypeScript | 第一章:环境搭建及基础数据类型

梁龙先森

typescript 前端 七日更

十日谈:我的 2020

escray

2020 日更挑战 十日谈

欧盟推出新数字法案,会是一场“锄强扶弱”的数字监管变革吗?

脑极体

今天发的被删了,不是我没写

lidaobing

28天写作营

生产环境全链路压测建设历程 16:淘宝网高可用历程的总结

数列科技杨德华

全链路压测 七日更

FGC青蛙钱包系统开发|FGC青蛙钱包软件APP开发

开發I852946OIIO

系统开发

阿里不允许使用 Executors 创建线程池!那怎么使用,怎么监控?

小傅哥

Java JVMTI 线程池 七日更 Executors

创业感悟 | 2021是继续打工还是选择创业?

黑马腾云

创业

既生 var 何生 let

喵叔

七日更

架构师 3 期 3 班 -week5- 总结

zbest

总结 week5

架构师 3 期 3 班 -week5- 作业

zbest

作业 week5

vivo 商城架构升级-SSR 实战篇

vivo互联网技术

前端 服务端 Node SSR

Flutter动态创建UI实现方案

FisherJoe

架构的业务属性

soolaugust

架构 设计 架构师 七日更

灵魂一击!详解Java中的IO输入输出流

程序员小毕

Java 程序员 架构 io

程序员告诉你:C/C++后台开发需要学习哪些技能书

赖猫

c++ Linux 后台开发

和 lvgo 一起学习设计模式.PDF

lvgo

Java 设计模式 23种设计模式

第十三周 作业

熊桂平

极客大学架构师训练营

有赞业务对账平台的探索与实践-InfoQ