作者 | 闲鱼技术 - 雨成

文章来源 | 闲鱼技术团队

1.现状

闲鱼作为一款闲置交易APP,在二手交易市场中是当之无愧的佼佼者。闲鱼从2014年诞生到现在七整年间持续增长,在这高速增长的背后带来的是每天近百亿的曝光点击浏览等数据,在这些数据规模如此庞大的背后也会带来诸多关于实时性的问题:

  • 用户反馈商品曝光异常,如何快速定位?
  • 产品同学圈了一批商品,如何查看该样本的实时报表?
  • 发现问题总是晚一步,如何在第一时间获取自定义的预警信息?
  • ……

为了解决上述的这些问题,我们开始了打造闲鱼实时数仓的探索之路。

2.实时数仓调研

数仓调研

在开始设计闲鱼的实时数据仓库之前,我们也调研了集团内外的各种数据仓库的设计与架构,一些是比较老的架构设计,另外一些是由于技术突破后进而带来的创新性的解决方案。本文不妨将这些实时数据仓库的新老设计做一下分类:

  • 第一类:从无到有
  • 当Apache Storm(开源的分布式实时计算系统)问世后,大数据不在依靠MapReduce这种单一的计算方式,拥有了当日数据当日处理的能力。
  • 第二类:从有到全
  • 以Lambda和Kappa为代表的架构,能够将实时与离线架构结合在一起,一套产品可以实现多种数据更新策略。
  • 第三类:从全到简
  • 以Flink为代表的支持窗口计算的流式框架出现,使离线和实时的逻辑能够统一起来,一套代码实现两种更新策略,避免了因为开发方式不统一导致的数据不一致问题。
  • 第四类:架构走向工具
  • 以Hologres为代表的HSAP(Hybrid Serving/Analytical Processing)引擎,用服务分析一体化的设计理念,统一分析型数据库和业务数据库,再配合Flink,真正实现数仓的彻底实时化。

首先我们摒弃了比较古老的方案,由于现在的技术创新非常快,涌现出很多优秀的产品可供我们去使用,另外基于闲鱼自身的业务需求,最终选择了Hologres[1]+Blink[2]来构建实时数据仓库。

数据模型

不管是从计算成本,易用性,复用性,还是一致性等方面,我们都必须避免烟囱式的开发模式,而是以中间层的方式去建设实时数仓,烟囱式架构有很大弊端,它无法与其他系统进行有效协调工作,不利于业务沉淀,而且后期维护成本非常大。下图展示了闲鱼实时数仓的数据模型设计架构图。

从上图可以看出我们将实时数仓的数据模型分为4层,自底向上依次为ODS、DWD、DWS和ADS。通过多层设计可以将处理数据的流程沉淀在各层完成。比如在数据明细层统一完成数据的过滤、清洗、规范、脱敏流程;在数据汇总层加工共性的多维指标汇总数据,提高了代码的复用率和整体生产效率。同时各层级处理的任务类型相似,可以采用统一的技术方案优化性能,使数仓技术架构更简洁。下面对这四层进行简单的介绍:

  • ODS(Operational Data Store): 贴源层
  • 这一层又叫做贴源层,最为接近数据源的一层,需要存储的数据量是最大的,存储的数据也是最原始。对众多数据源而言,他们的数据格式基本不一致,经过统一规格化后可以得到规整的数据,将数据源中的数据经过抽取、清洗、传输后装入ODS层。
  • DWD(Data Warehouse Detail):数据明细层
  • 业务层与数据仓库的隔离层,主要对ODS层做一些数据清洗和规范化的操作,并且可以按照不同的行为维度对数据进行划分,例如本文对数据源就进行了划分,主要分为浏览、曝光、点击、交易等不同的维度,这些不同的维度能够对上层调用方提供更细粒度的数据服务。
  • DWS(Data WareHouse Servce):数据服务层
  • 对各个域进行了适度汇总,主要以数据域+业务域的理念建设公共汇总层,与离线数仓不同的是,实时数仓的汇总层分为轻度汇总层和高度汇总层,例如将轻度汇总层数据写入 ADS,用于前端产品复杂的OLAP查询场景,满足自助分析和产出报表的需求。
  • ADS(Application Data Store):应用数据服务层
  • 主要是为了具体需求而构建的应用层,通过 RPC 框架对外提供服务,例如本文中提到的数据报表分析与展示、监控告警、流量调控、开放平台等应用。
  • DIM(Dimension):维表
  • 在实时计算中非常重要,也是重点维护的部分,维表需要实时更新,且下游基于最新的维表进行计算,例如闲鱼的实时数仓维表会用到闲鱼商品表、闲鱼用户表、人群表、场景表、分桶表等。

3.技术方案

整体架构

上面对闲鱼实时数仓的数据模型进行了解剖并详细地介绍了模型的各层次设计思想和实际运用。下面是根据数据模型构建的技术架构图,共分为五个层次,自底向上分别为数据源、数据接入层、数据计算层、数据服务层和应用层。

数据源是整个实时数仓的底座,闲鱼拥有众多场景,例如首页推荐、猜你喜欢、搜索等,在这些场景中会有不同的用户行为,用户产生的曝光、点击、浏览等行为日志会被上层存储工具收集。如上图中的数据接入层,可以将数据源接入到UT[3]日志、黄金令箭、数据备库或服务端日志中存储。

数据清洗与规整是构建实时数仓的核心过程,数据计算层利用Blink的实时处理能力将不同格式的数据统一清洗、补充和规整后存入TT[4]中。数据服务层是实时数仓的网关层,将实时数据进行逻辑处理后对外提供数据服务和API网关能力。

应用层是最贴近用户的层次,这一层是为了具体需求而构建的,可以对各个维度数据进行实时报表展示,对线上异常流量监控告警,对商品域进行流量调控,还可供其他应用开放相关接口等。

技术难点

整体的技术架构如上图所示,构建实时数仓的关键是实时数据处理以及实时交互的能力,闲鱼每日产生近百亿的埋点数据以及服务器日志,在构建实时数仓有以下关键难点:

  • 数据量大,需要处理的埋点数据以及服务器日志达百亿。
  • 实时性能要求高,监控告警需要较高的实时性。
  • 分析交互需求强,数据分析场景复杂且交互频繁。
  • 异构数据源多,闲鱼各个系统模块产生各类格式的数据。

首先如何能够即稳定又高效地处理数据是我们亟待解决的问题,在面临海量数据计算处理时,我们选用了集团内部的流式计算框架Blink,它是基于开源框架Flink的再封装的新一代流式计算引擎,经过多年双11的考验,其实时计算能力对我们系统来说是毋庸置疑的。

我们在做实时报表展示时结合性能和实际情况,会对实时数据进行分钟级别的数据聚合,通过Blink提供的滚动窗口聚合就能够高效地解决该问题。滚动窗口将每个元素分配到一个指定窗口大小的窗口中,滚动窗口有一个固定的大小,并且不会出现重叠。例如:如果指定了一个1分钟大小的滚动窗口,那么无限流的数据会根据时间划分成[0:00 - 0:01), [0:01, 0:02), [0:02, 0:03)… 等窗口,滚动窗口划分形式如下图所示。

我们在编写分钟级别的Blink任务时,只需要在 GROUP BY 子句中定义滚动窗口即可,伪代码如下:

GROUP BY TUMBLE(<time-attr>, <size-interval>)

上述SQL中的参数必须是流中的一个合法的时间属性字段,有两种类型:processing time 或是 event time。

  • Event Time:用户提供的事件时间(通常是数据的最原始的创建时间),event time一定是用户提供在表的schema里的数据。
  • Processing Time:表示系统对事件进行处理的本地系统时间,单位为毫秒。

根据项目实际情况,因为我们聚合的是埋点事件当时的数据,所以选择使用Event Time,选择该类型时间的另一好处是在重跑某个时间段的任务时也能够保持结果的一致性。

通过Blink的这个法宝我们能够高效实时地处理海量数据,那在面临数据分析场景复杂并且交互非常频繁的这种情况下,我们又如何去避免传统OLAP的存储计算弊端呢?在寻找实时的并且兼并服务/分析一体化的系统工具时我们发现了一款利器,它就是Hologres(Holographic+Postgres),它支持对万亿级数据进行高并发低延时多维分析透视和业务探索,可以轻松而且经济的使用现有BI工具分析所有数据,在面临PB级数据时依然能够保持秒级响应的能力,并且简单易用,能够快速上手。

Hologres是基于存储计算分离的设计模式而构建的,数据全部存在一个分布式文件系统中,存储引擎的总体架构如下图所示:

每个分片(shard)构成了一个存储管理和恢复的单元(recovery unit),上图展示了一个分片的基本架构,一个分片由多个tablet组成,这些tablet会共享一个日志(Write-Ahead Log,简称WAL,所有的新数据都是以append-only的形式插入的。当写操作不断进来,每个tablet里会积累出很多文件。当一个tablet里小文件积累到一定数量时,存储引擎会在后台把小文件合并起来,能减少使用系统资源且合并后的文件减少了,提高了读的性能,为实时高效分析提供了可能性。

上面详细描述了海量数据的实时处理、数据存储以及分析的解决方案,那在面对异构数据源接入又是如何处理的呢?闲鱼由于场景众多,业务复杂,在处理异构数据源时我们采用领域维度统计的方式,将不同领域的各类数据源字段统一化,在Blink清洗数据时会结合场景、人群、分桶等维度信息来解决异构数据源的问题。

由上图可知,领域模块主要分为流量域、用户域、交易域、互动域等,每个领域中都会抽象出相应的对象,例如流量域中有商品、广告和运营投放;用户域中有用户、设备、卖家和买家;交易域中有询单、成交、GMV;互动域中有收藏、超赞和评论。

在设计异构数据源的解决方案时也考虑到后面打造开放平台的需求,所以将数据接入层抽象成不同领域的接口对外提供接入服务并且在应用层也开放了各个维度的统计接口。这样对有接入实时数仓的业务需求时可以通过数据层和应用层开放的抽象接口快速接入,不用考虑整个链路中间的细节,能够极大地减少开发周期。

4.阶段性成果

本文中所构建的实时数仓在实时报表,曝光异常反馈等方面有所应用,通过平台可以实时地浏览系统大盘、首页、猜你喜欢、搜索等场景的各个维度数据,提升了闲鱼各个场景的实时数据的丰富度。目前通过实时数仓的应用,也取得了一些成果:

  • 能够实时评估线上策略的最终效果;
  • 能够快速排查定位用户反馈的曝光异常问题;
  • 能够给产品同学提供圈品后的实时报表信息等等。

5.展望

目前我们对实时数仓