0%

实时数仓建设

实时数仓概念

实时数仓:以端到端低延迟、SQL 标准化、快速响应变化、数据统一为目标。

一个通用的实时生产平台跟一个通用交互式实时分析引擎相互配合,同时满足实时和准实时业务场景。两者合理分工,互相补充,形成易开发、易维护且效率高的流水线,兼顾开发效率与生产成本,以较好的投入产出比满足业务的多样性需求。

在传统的 BI 体系中,基于离线大数据构建数据仓库的过程,大部分是 T+1 的隔日离线计算。即每天凌晨开始从原始日志数据构建数仓,将多层级的离线计算任务,通过工作流系统进行串联。数仓构建任务失败后可以有由工作流系统触发任务重跑。一般来说,离线数仓构建任务的失败重跑,只影响数据生产出来的时间,不影响数据的完整性、正确性。

实时数仓 vs. 离线数仓实时数仓 vs. 离线数仓

实时仓库的核心有以下几个特点:

  • 重视数仓的水平拆分

    离线数仓中,数据的载体是 Hive 表,借助 Hive 的分区字段和谓词下推机制,我们可以在各个层级构建一些稍大的表,而将关键的维度字段设置成分区,使用户在查大表的时候达到查小表的效果。在实时数仓中,数据的载体是 Kafka 队列,如果向用户提供一个大流,需要用户在消费数据实时过滤出其中的一小部分数据进行使用,那么对 Kafka 的带宽资源和 Flink 的计算资源都是极大的浪费。

    所以,我们需要尽量将常用的维度进行水平拆分构建

  • 重视维度退化

    在离线数仓中,一个维度放在事实表里还是放在维度表里是一件可权衡的事情。一些不太常用的维度可以保留在维度表里,让用户查询使用时再进行 Join。而在建设实时数仓时应该尽量帮助数据下游方减少这些代价,提前将会用到的维度退化到数仓的事实流中,将实时流变成一个宽流,避免下游业务方在使用数据时,自行去处理流 Join 外部表的这类复杂场景。

  • 重视层级缩短

    在实时数仓的构建过程中,数据在多层级 Kafka 中传递,数据处理的链路越长,数据的延迟越大、稳定性越差。因此,在实时数仓中,要尽可能引导用户使用短链路生产的实时数据。

实时技术选型

目前,市面上已经开源的实时技术还是很多的,比较通用的有 Storm、Spark Streaming 以及 Flink。从技术成熟度来说,前几年的 Storm,在性能稳定性、可靠性以及扩展性上是无可替代的。但随着 Flink 越来越成熟,从技术性能上以及框架设计优势上已经超越了 Storm,从趋势来讲就像 Spark 替代 MapReduce 一样,Storm 也会慢慢被 Flink替代。

Storm vs. FlinkStorm vs. Flink

实时架构

Lambda 架构

Lambda 架构Lambda 架构

Lambda 是比较经典的一款架构,以前实时的场景不是很多,以离线为主,当附加了实时场景后,由于离线和实时的时效性不同,导致技术生态是不一样的。而Lambda 架构相当于附加了一条实时生产链路,在应用层面进行一个整合,双路生产,各自独立。在业务应用中,顺理成章成为了一种被采用的方式。

双路生产会存在一些问题,比如加工逻辑 Double,开发运维也会 Double,资源同样会变成两个资源链路。因为存在以上问题,所以又演进了一个 Kappa 架构。

Kappa 架构

Kappa 架构Kappa 架构

Kappa 从架构设计来讲,比较简单,生产统一,一套逻辑同时生产离线和实时。但是在实际应用场景有比较大的局限性,在业内直接用 Kappa 架构生产落地的案例不多见,且场景比较单一。

架构设计

在业务早期,为了满足业务需要,一般是 Case By Case,先把需求完成。业务对于实时性要求是比较高的,从时效性的维度来说,没有进行中间层沉淀的机会。在这种场景下,一般是拿到业务逻辑直接嵌入,这是最简单有效的方法,在业务发展初期这种开发模式也比较常见。

业务早期架构业务早期架构

如上图所示,拿到数据源后,我们会经过数据清洗、扩维,通过 Storm 或 Flink 进行业务逻辑处理,最后直接进行业务输出。把这个环节拆开来看,数据源端会重复引用相同的数据源,后面进行 ETL 清洗、过滤、扩维等操作,都要重复做一遍。唯一不同的是业务的代码逻辑是不一样的,如果业务较少,这种模式还可以接受,但当后续业务量上去后,会出现谁开发谁运维的情况,维护工作量会越来越大,作业无法形成统一管理。而且所有人都在申请资源,导致资源成本急速膨胀,资源不能集约有效利用,因此要思考如何从整体来进行实时数据的建设。

所以,如何来构建实时数仓呢?首先要进行拆解,有哪些数据,有哪些场景,这些场景有哪些共同特点。例如下图的,日志类业务类

  • 日志类:数据量特别大,半结构化,嵌套比较深。日志类的数据有个很大的特点,日志流一旦形成是不会变的,通过埋点的方式收集平台所有的日志,统一进行采集分发,就像一颗树,树根非常大,推到前端应用的时候,相当于从树根到树枝分叉的过程(从 1 到 n 的分解过程)。如果所有的业务都从根上找数据,看起来路径最短,但包袱太重,数据检索效率低。日志类数据一般用于生产监控和用户行为分析,时效性要求比较高,时间窗口一般是 5min 或 10min,或截止到当前的一个状态,主要的应用是实时大屏和实时特征,例如用户每一次点击行为都能够立刻感知到等需求。
  • 业务类:主要是业务交易数据,业务系统一般是自成体系的,以 Binlog 日志的形式往下分发,业务系统都是事务型的,主要采用范式建模方式。特点是结构化,主体非常清晰,但数据表较多,需要多表关联才能表达完整业务,因此是一个 n 到 1 的集成加工过程。

日志类和业务类的场景一般是同时存在的,交织在一起,无论是 Lambda 架构还是 Kappa 架构,单一的应用都会有一些问题。因此针对场景来选择架构与实践才更有意义。


基于以上问题,可以使用流批结合的方式来应对不同的业务场景。

如上图所示,数据从日志统一采集到消息队列,再到数据流的 ETL 过程,作为基础数据流的建设是统一的。之后对于日志类实时特征,实时大屏类应用走实时流计算。对于 Binlog 类业务分析走实时 OLAP 批处理。

流式处理分析业务的痛点是什么?对于范式业务,Storm 和 Flink 都需要很大的外存,来实现数据流之间的业务对齐,需要大量的计算资源。且由于外存的限制,必须进行窗口的限定策略,最终可能放弃一些数据。计算之后,一般是存到 Redis 里做查询支撑,且 KV 存储在应对分析类查询场景中也有较多局限。

实时 OLAP 怎么实现?有没有一种自带存储的实时计算引擎,当实时数据来了之后,可以灵活的在一定范围内自由计算,并且有一定的数据承载能力,同时支持分析查询响应呢?随着技术的发展,目前 MPP 引擎发展非常迅速,性能也在飞快提升,所以这里使用的是 Apache Doris 引擎。


其实实时和离线数仓是相似的。开始都是 Case By Case,当数据规模涨到一定的程度时,就会考虑如何进行治理。而在如何进行管理的问题上,首先考虑的就是分层的处理逻辑:

  • 数据贴源层:在数据源的层面,离线和实时在数据源是一致的,主要分为日志类和业务类,日志类又包括用户日志、DB 日志以及服务器日志等。
  • 实时明细层:在数据明细层,为了解决重复建设的问题,要进行统一构建,利用离线数仓的模式,建设统一的基础明细数据层,按照主题进行管理,明细层的目的是给下游提供直接可用的数据,因此要对基础层进行统一的加工,比如清洗、过滤、扩维等。
  • 数据汇总层:汇总层通过 Flink 或 Storm 的简洁算子 Transformer 直接可以算出结果,并且形成汇总指标池,所有的指标都统一在汇总层加工,所有人按照统一的规范管理建设,形成可复用的汇总结果。

平台化建设

架构确定之后,后面考虑的是如何进行平台化的建设,实时平台化建设是完全附加于实时数仓管理之上进行的。

首先进行功能的抽象,把功能抽象成组件,这样就可以达到标准化的生产,系统化的保障就可以更深入的建设,对于基础加工层的清洗、过滤、合流、扩维、转换、加密、筛选等功能都可以抽象出来,基础层通过这种组件化的方式构建直接可用的数据结果流。通过冗余的方式可以提高生产效率,是一种以空间换时间思想的应用。

通过基础层的加工,数据全部沉淀到 IDL 层,同时写到 OLAP 引擎的基础层,再往上是实时汇总层计算,基于 Storm、Flink 或 Doris,生产多维度的汇总指标,形成统一的汇总层,进行统一的存储分发。

当这些功能都有了以后,元数据管理,指标管理,数据安全性、SLA、数据质量等系统能力也会逐渐构建起来。

Reference

[1] 美团外卖实时数仓建设实践