2019新春支付宝红包技术大揭秘 之 极速核对数据传输之战

本文作者,纪勇,花名竹箐,蚂蚁金服技术专家。

2014 年加入蚂蚁金服,前期主要负责缓存中间件,多次参与保障双十一大促稳定性。近一年主要负责 Light 链路的建设,构建准确、高效、实时的 DB 数据采集链路。


本文根据《2019 新春支付宝红包技术大揭秘》线上峰会分享整理,关于本次分享更多主题,可以详见文末回顾链接。



前言

五福走到今年已经是第四年了,有 1 亿人从第一年就开始集五福,连续三年都参加。今年超过 4.5 亿人参与,每 3 个中国人就有 1 个在集福送福。

新春红包极速核对数据传输之战,其实想和大家谈谈数据传输链路做了哪些优化和改进来满足新船红包的极速核对需求的。

首先一个问题:

相信大部分人今年都集齐了五福。在 2016 年支付宝红包首次推出新春红包的时候,敬业福发放的较少,最终只有不到 80W 人集齐了五福,当时还有很多关于敬业福的段子,最终这些幸运儿平分了 2.15 亿的奖金。红包活动的玩法在最近几年也发生了比较大的改变,2019 年参与五福的人数达到了 4.5 亿人左右,同时奖金也是用拼手气的方式进行发放的。

五福红包从大惊喜向小确幸的转变,同时带来了五福红包对技术的挑战:

  • 第一数据量增加了上百倍。从 80W 到 4.5 亿。
  • 第二计算金额的逻辑也相对比较复杂。从均分红包到现在的随机发放。

活动复杂度的增加让核对变得更加关键了。核对就像是业务的保护伞一样,在业务发生前以及业务发生后都保护着业务:在业务发生前防止异常业务的推进;在业务发生后及时报告异常业务,尽快止血。

背景

我们首先了解一下核对的基本实现,一般来说核对主要有两个依赖:

  • 数据链路
  • 计算能力

即核对系统首先通过数据链路获取核对业务所需的数据,然后通过计算(批处理或者流式计算)来确认一笔业务是否异常。

数据链路一般包含几种:

  • 业务主动发起服务调用告知核对系统。
  • 核对系统采集业务日志。
  • 核对系统采集业务数据库的增量数据(例如 MySQL binlog)

无疑数据库的增量数据是真实业务落地的体现,本文主要讲的是数据库增量链路的改造和优化。涉及的概念列举如下:

  • 物理表:对应具体数据源里的某张表。
  • 逻辑表:可以包含一个或者多个相同结构的物理表,在业务上看是一个视图。分库分表可以认为是一个逻辑表对应多个物理表的体现。
  • 逻辑表拓扑:指的是一张逻辑表关联了哪些物理表,拓扑在某些场景下是会变化的(例如数据库拆分、数据库迁移等)。
  • 全量数据:全量数据指一张表现存的所有数据。
  • 增量数据:广义上来说某个时间点后发生变更的数据就是增量数据,是相对于全量数据的一个概念。本文主要指通过数据库 binlog 采集的数据。
  • 安全位点:和流计算里的 watermark 比较像。一条数据的安全位点表示当接收到这条数据时,这条流上安全位点之前的数据都已到达。

这里我们简单介绍一个核对场景,A 转账 100 元给 B,整个核对业务的处理逻辑如下(此处只是举例,实际核对场景远比例子复杂):

  1. 通过数据链路接收到 B 的一条入账记录,来源是数据库 binlog 的一条转账记录,包含的信息有:转出方 A、转入方 B、转账金额 100 元、发生时间 2019-03-07 12:00:00。
  2. 等待账务记录的增量数据流安全位点抵达 2019-03-07 12:00:00(即 2019-03-07 12:00:00 之前的账务变更都已全部到达)。
  3. 校验 A 的账务变更是否存在,并校验变更后的金额是否比变更前减少 100 元。
  4. 校验 B 的账务变更是否存在,并校验变更后的金额是否比变更前增加 100 元。

其中 1、2 两步是前文所说的数据链路,3、4 是前文所说的计算能力。如果 3、4 的计算都通过则认为这笔转账记录核对通过,否则为业务异常。

对于新春红包核对,我们的目标主要有三个:

  1. 五福卡和合成卡之间的核对,保证发卡逻辑的正确性。
  2. 领奖金额和发奖金额之间的核对,保证算奖逻辑的正确性。
  3. 发奖金额和账务流水之间的核对,保证发奖逻辑的正确性。

只有保证上述三个业务逻辑的正确,才能保证春节红包的奖金不多发、不少发、不错发。

同时新春红包活动也给核对提出了一些要求:

  1. 时效性,要求整个核对在 15 分钟内完成,增量数据 2 分钟内全部抵达核对系统,否则会影响发奖时间。
  2. 准确性,要求到达核对系统的数据必须和数据库产生的增量数据完全一致,否则核对结果不可信。
  3. 吞吐上,要求在 2 分钟内完成上百亿数据的传输,TPS 达到了上千万。

老架构

解决的问题

老架构是以 Store 为核心的,Store 可以理解是一个数据库 binlog 备份,给下游系统提供订阅数据库增量数据的能力,那么为什么不让业务直接拉取数据库 binlog,有以下三方面的考虑:

  1. 连接数上,如果所有需要增量数据的系统都来连接数据库,势必给数据库带来比较大的压力,影响线上业务的稳定性。
  2. 过滤数据,下游所需的增量数据往往以逻辑表为单位,而数据库 binlog 不具备数据过滤的能力,如果下游拉取所有数据在客户端过滤则对网络带宽非常不友好。
  3. 数据格式,蚂蚁内部存在多种数据库类型(OceanBase、MySQL、Oracle),每种数据库的增量数据的获取方式以及数据格式上都存在差异,如果让下游业务直接面对多种数据库类型,将大大增加下游系统的复杂性。

因此我们构建 Store 作为数据库增量数据的备份为下游提供数据订阅服务,Store 的能力列举如下:

  1. 使用单连接消费数据库的增量数据供下游消费,大大减少了数据库上的 binlog 连接数,增强了线上数据库的稳定性。
  2. 拉取到的数据建立库表维度的索引,方便下游只消费部分库表的数据,Store 完成过滤发送给下游,节省网络带宽。
  3. 屏蔽了各个数据增量数据格式的差异,拉取到的增量数据统一转换为 Store 自定义的数据格式,为下游提供无差别的数据库增量数据订阅服务。

存在的问题

这套 Store 的架构在蚂蚁内部已经服务多年,给下游提供稳定的增量数据订阅服务。在蚂蚁业务及系统架构逐步发展的情况下,今年这个数据架构已无法满足下游订阅数据的要求,尤其是新春红包这种大规模的业务。

随着蚂蚁的业务发展,架构上主要有以下几个特点:

  1. 分库分表多,蚂蚁现有的日常业务体量已经非常大了,核心系统的分库分表数极多。在双十一、双十二、618 等大促活动的时候更是要把大量的业务弹到云上,使用云上的资源节省成本;三地五中心的容灾架构也增加了部分同城、异地灾备库。这些都大大增加了蚂蚁的分库分表数量。,蚂蚁最核心的业务一张逻辑表会关联上千个物理表。
  2. 消费下游多,在大数据时代,数据的使用方式非常多,各类数据会被各种下游业务订阅计算。
  3. 重复消费多,同一张逻辑表可能被数仓、核对、搜索、业务订阅多次,造成了逻辑表消费的膨胀。
  4. 数据倾斜多,我们前面提到,蚂蚁核心业务有弹性库、灾备库等,但是这些库平常是没有业务流量的,这就导致下游数据消费倾斜的比较厉害,就是说某些平时没有流量的库由于弹性、容灾等原因突增大流量,对下游的负载均衡是一个挑战。另外分库分表数和数据量往往不是正比关系(为了做事务导致一些数据量小的表需要和大表一样的拆分数),导致下游的资源更加不好调配。

这些原因导致了大流量在老的架构下会出现一些问题,例如:

  • 由于分库分表多,下游即使订阅的逻辑表数据量不大,仍然需要大量的资源。
  • 连接数过多导致 Store 过滤数据触发 CPU 瓶颈,吞吐变低导致下游延迟。
  • 数据倾斜导致下游系统需要频繁的做负载调整,一定程度上影响了数据时效性。

这些问题都导致老架构无法满足新春红包所需的低延迟、高吞吐的需求,因此架构亟需改进以满足新春红包对核对的需要。

新架构(DWS)

DWS:Database and Data Warehouse Synchronization ,即数据(仓)同步服务。

解决的问题

通过对老架构及蚂蚁架构特点的解读,我们发现老架构上需要解决的问题如下:

  • 减少整体连接数以节省资源。
  • 减少数据过滤消除 Store 的 CPU 瓶颈。
  • 重新定义分区,并在分区间平衡数据以提升下游的吞吐。

问题的根源我们认为是 Store 的数据存储方式不适合现有大多数下游的消费方式,前文说过 Store 可以认为是数据库 binlog 的备份,它是按照数据库事务的方式来组织数据的,而九成以上的下游消费数据都是逻辑表的维度,正是这种数据组织上的差异导致了架构问题。按照逻辑表的维度组织数据我们想到了消息的 Topic,因此我们引入了消息队列作为我们数据的存储,同时 Topic 上的队列概念也有助于我们对数据重新定义分区。

在新架构下我们以消息队列为中心,提供了以下能力:

  • 数据按照逻辑表的维度组织,一个逻辑表的增量数据对应一个消息 Topic。
  • 数据在 Topic 上重新分区,按照主键 hash 投递到不同的 queue 上,保证了同一主键顺序的正确性,同时各个 queue 之间的数据均衡。
  • 逻辑表的分区数不由分库分表数决定,而是按照数据量、TPS 重新定义 queue 数,节约下游消费资源。

架构的升级实际上是将下游对逻辑表维度的消费需求和老架构下 Store 事务维度存储数据进行了解耦,方法是在中间增加了一层消息队列。

存在的问题

一般来说非划时代的架构变更都会在解决老问题的同时,带来一些新的问题(tradeoff),那么新架构实际上也存在以下几个问题:

  1. 安全位点问题,由于 Store 是作为 binlog 的备份,Store 中的数据顺序就是数据库事务顺序,因此在 Store 上消费数据可以认为是时间序列递增的,拿到数据之后根据数据时间就知道数据的安全位点。但是新架构下消息队列上的数据实际上来自多条 Store 数据流,数据时间是乱序的,数据时间无法再作为安全位点使用。
  2. 成本问题,老的架构下 Store 是存储和计算一体的,新的架构下我们保留了 Store 的同时,又增加了 Dispatcher(计算节点)以及消息队列(轻计算和重存储),这些成本的增加如何消除。

由于时间问题,我们以安全位点为例看看新架构产生的问题我们如何解决。

安全位点问题

增量数据链路对安全位点都有较强的需求,如对账系统、核对系统,另外还包括很多天级的数据任务,因此新架构下的必须解决安全位点的问题。

一个消息队列 queue 的数据来源于多个 Store,我们需要协调多个 Store 的安全位点才能知道这条数据的安全位点,也就是说当 Dispatcher 发送一条数据到消息队列时,此条数据的安全位点就是所有可能发往此消息队列的 Dispatcher 里位点最小的一个。

例如,假设我们有 4 个 Dispatcher 往 queue2 发数据,Dispatcher 1、2、3 都已经发送到 10:00,Dispatcher 4 发送到 09:59,此时所有发往 queue2 的数据的安全位点都只能是 09:59。具体计算方法是当数据要发送到下游队列的时候,调用管控系统,由管控获取所有相关 Dispatcher 的位点并计算最小位点返回给 Dispatcher,作为此 Dispatcher 发送数据的安全位点。

这里依旧存在不小的难点:

  • 支付宝内部有大量的 Store,也就意味着有大量的 Dispatcher(10000+ Store)。
  • 每个 Dispatcher 内部有大量的逻辑表(平均 30+)。
  • 每个逻辑表关联大量的 Dispatcher(平均 30+)。
  • Dispatcher 位点保存在管控系统的 DB 中,用于进程重启时做断点重连,获取相关联 Dispatcher 的位点需两次数据查询。

查询到数据之后还要做计算才能获取安全位点,计算也是不可忽视的环节,因此我们分为两方面来做优化:数据查询和计算。

数据查询

按照上面提到的数据,查询一轮所有逻辑表的位点需要 30 30 10000 * 2 = 1800W 次查询。当然我们可以降低查询频率,在 Dispatcher 本地缓存安全位点,在接下来的一段时间内使用缓存的安全位点,但是这样势必会降低安全位点准确度,造成下游数据延迟(下游的计算需要执行,需要确认数据已到达)。因此这里需要在计算频度和准确度之间做一个权衡,我们的期望是将安全位点的计算延迟降低到 10s 以内,因此数据查询就是 180W 次/s。

此处的优化策略也是比较简单的,大量使用缓存,减少数据查询成本,增加数据查询速度。此处我们使用内部分布式缓存增加查询速度,最终缓存承担了大量的数据访问,将 DB 查询控制在可以接受的范围内。

缓存访问次数:

计算

要减少计算就要结合实际场景看是否有些计算是没有必要的,我们分析了逻辑表的组合可以看到单个 Dispatcher 上的逻辑表拓扑大致相同,这是因为一个数据库实例往往服务于一个或者多个业务,这些业务使用的多张表的分库分表基本一致(主要是考虑需要在物理库内部做事务,否则会牵涉到分布式事务,加大系统复杂度)。也就是说大多数的逻辑表安全位点是不需要重新计算的,基于这种业务场景,我们将一个 Dispatcher 内部的多个逻辑表按照拓扑归类,计算安全位点只需要按照类别维度计算即可,这样可以将计算维度降低一个数量级(同时也减少了数据访问)。

通过对数据查询、计算的优化最终将安全位点的延迟降低到 10s 以内,为 2 分钟完成数据同步的目标做了较大的贡献。

数据校验

上一小节中我们主要讲了新的链路是如何满足新春红包核对业务对数据链路的时效要求的,在此小节中我们主要关注数据准确性方面。如果说数据链路的时效性、高吞吐是 0 的话,数据质量则是众多 0 前面的 1,如果无法保证数据的质量,高时效性、高吞吐量是没有人买单的。

在数据质量上,考虑到下游消费方非常多,想要提供多种下游的数据校验是非常困难的,而且下游消费方对他们自己的业务更加理解。因此我们决定不提供具体的产品,只提供数据查询的服务,把具体的校验交给各个下游来做。

和全量数据的校验对比,增量数据的校验有其独特的特点:

  • 时效性高,数据产出立即被使用,核对需要非常及时。
  • 有效期短,增量校验往往只需要对比最近一小段时间的数据。

基于以上两个特点我们决定在内存中构建增量数据的索引,并提供给下游做多种维度的数据查询,由于整体数据量较大,因此我们在内存构建的是索引 + 时间 + checksum 的数据,提供给下游快速的基于已有索引的分时段数据查询服务,下游使用此服务得到的数据和自身的数据做对比即可校验数据正确性。此外,我们分时段的数据采用时间分区作为分库分表键,过期数据直接删除物理表即可。

我们使用 DWS-Connector 将 DWS 中的数据从消息队列传输到内存索引系统,DWS-Connector 以框架 + 插件化的方式提供 DWS 到多种数据源的连接,这也给整个 DWS 后续生态的拓展提供了基础。

总结

从以上的分析我们可以看到实时数据链路通过各种改造支撑新春红包极速核对的需要,总结来看主要有以下几点:

  • 在数据传输上,将数据从 OLTP 友好改造为 OLAP 友好的组织方式,更加符合大多数下游消费数据的需要。
  • 在数据质量上,构建 DWS 数据的分时段快速查询服务,供下游做实时的数据准确性校验。
  • 在后续拓展上,开发 DWS-Connector 框架,连接多种下游数据源,给用户提供更加全面的数据传输服务。

彩蛋

DWS 除了服务于新春红包极速核对之外,在蚂蚁内外部也有广泛的使用场景,这里简单举几个例子说明

数据库同步

DWS 支持同构、异构数据库的同步,在内部服务于 MySQL/Oracle -> OceanBase 的迁移服务,已稳定运行五年时间。近一年也帮助很多外部客户完成传统数据到分布式数据库 OceanBase 的迁移服务。

其他存储的复制服务

DWS 能够将数据库的数据复制到多种异构存储,如 ElasticSearch、Redis、HDFS 等。帮助用户轻松的在数据库数据之上构建检索、缓存、分析等服务。

订阅

DWS 同时提供数据库增量数据订阅服务,用户可以通过 DWS 客户端获取数据库增量变更后自定义处理逻辑,例如触发一个 RPC 服务、发送一条消息等,任何需要感知数据库数据变更的场景都可以使用 DWS 的服务。


数据(仓)同步服务 DWS(Database and Data Warehouse Synchronization) 将在3月底进行公测,敬请期待。

关于《2019 新春支付宝红包技术大揭秘》更多主题,可以点击链接进行查看:

tech.antfin.com/activities/…


猜你喜欢

转载自juejin.im/post/5c81ce756fb9a049fa108e60