乐趣区

关于数据湖:字节跳动基于-Apache-Hudi-的多流拼接实践方案

字节跳动数据湖团队在实时数仓构建宽表的业务场景中,摸索实际出的一种基于 Hudi Payload 的合并机制提出的全新解决方案。

作者:字节跳动数据湖团队
字节跳动数据湖团队在实时数仓构建宽表的业务场景中,摸索实际出的一种基于 Hudi Payload 的合并机制提出的全新解决方案。

该计划在存储层提供对多流数据的关联能力,旨在解决实时场景下多流 JOIN 遇到的一系列问题。接下来,本文会具体介绍多流拼接计划的背景以及实践经验。

业务面临的挑战

字节跳动存在较多业务场景须要基于具备雷同主键的多个数据源实时构建一个大宽表,数据源个别包含 Kafka 中的指标数据,以及 KV 数据库中的维度数据。

业务侧通常会基于实时计算引擎在流上做多个数据源的 JOIN 产出这个宽表,但这种解决方案在实践中面临较多挑战,次要可分为以下两种状况:

  1. 维表 JOIN
  2. 场景挑战:指标数据与维度数据进行关联,其中维度数据量比拟大,指标数据 QPS 比拟高,导致数据可能会产出提早。
  • 以后计划:将局部维度数据缓存起起来,缓解高 QPS 下拜访维度数据存储引擎产生的工作背压问题。
  • 存在问题:因为业务方的维度数据和指标数据时间差比拟大,所以指标数据流无奈设置正当的 TTL;而且存在 Cache 中维度数据没有及时更新,导致上游数据不精确的问题。
  1. 多流 JOIN
  • 场景挑战:多个指标数据进行关联,不同指标数据可能会呈现时间差比拟大的异常情况。
  • 以后计划:应用基于窗口的 JOIN,并且维持一个比拟大的状态。
  • 存在问题:维持大的状态不仅会给内存带来的肯定的压力,同时 Checkpoint 和 Restore 的工夫会变 得更长,可能会导致工作背压.

    剖析与对策

    总结上述场景遇到的挑战,次要可归结为以下两点:

  • 因为多流之间时间差比拟大,须要维持大状态,同时 TTL 不好设置。
  • 因为对维度数据做了 Cache,维度数据数据更新不及时,导致上游数据不精确。

针对这些问题,并联合业务场景对数据提早有肯定容忍,但对数据准确性要求比拟高的背景,咱们在一直的实际中摸索出了基于 Hudi Payload 机制的多流拼接计划:

  • 多流数据齐全在存储层进行拼接,与计算引擎无关,因而不须要保留状态及其 TTL 的设置。
  • 维度数据和指标数据作为不同的流独立更新,更新过程中不须要做多流数据合并,上游读取时再 Merge 多流数据,因而不须要缓存维度数据,同时能够在执行 Compact 时进行 Merge,减速上游查问。

此外,多流拼接计划还反对:

  • 内置通用模板,反对数据去重等通用接口,同时可满足用户定制化数据处理需要。
  • 反对离线场景和流批混合场景。

计划介绍

基本概念

首先简略介绍下本计划依赖 Hudi 的一些外围概念:

  • Hudi MetaStore

这是一个中心化的数据湖元数据管理系统。它基于 Timeline 乐观锁实现并发写管制,能够反对列级别的抵触查看。这在 Hudi 多流拼接计划中可能实现并发写入至关重要,更多细节可参考字节跳动数据湖团队向社区奉献的 RFC-36。

  • MergeOnRead 表读写逻辑

MergeOnRead 表外面的文件蕴含两种,LogFile (行存) 和 BaseFile (列存),实用于实时高频更新场景,更新数据会间接写入 LogFile 中,读时再进行合并。为了缩小读放大的问题,会定期合并 LogFile 到 BaseFile 中,此过程叫 Compact。

原理概述

针对上述业务场景,咱们设计了一种齐全基于存储层的多流拼接计划,反对多个数据流并发写入,读时依照主键合并多流数据,此外还反对异步 Compact 来减速上游读取数据。


图 1 Hudi 多流拼接概念图(本文所有图中示例数据均与图 1 统一)

现以一个简略的示例流程对计划原理进行论述,图 1 为多流拼接示意图。图中的宽表蕴含 BCDE 五列,是由两个实时流和一个离线流拼接而成,其中 A 是主键列,实时流 1 负责写入 ABC 三列,实时 流 2 负责写入 AD 两列,离线流负责写入 AE 两列,此处仅对两个实时流的拼接过程进行介绍。

图 1 中显示两个流写入数据以 LogFile 模式存储,Merge 过程是合并 LogFile 和 BaseFile 中的数据。合并过程中,LogFile 中每一列的值被更新到 BaseFile 中对应的列上,BaseFile 中未被更新的列放弃原来的值不变,如图 1 中 BCD 三列被更新成新值,E 列放弃旧值不变。

写入过程

多流数据拼接计划反对多流并发写入,互相独立。对于单个流的写入,逻辑与 Hudi 原有写入流程统一,即数据以 Upsert 的形式写入 Hudi 表,以 LogFile 的模式存储,并在数据写入的过程中对数据去重。在多流写入的场景,外围点在于如何解决并发问题。

图 2 显示了数据并发写入的流程。流 1 和 流 2 是两个并发的工作,查看这两个工作写入的列除了主键以外是不是存在其它交加。例如:

流 1 的 Schema 蕴含三列 (A,B,C),流 2 的 Schema 蕴含两列 (A,D)。
在并发写入的时候,先在 Hudi MetaStore 对两个工作发动的 DeltaCommit 做列抵触查看,即除了主键列外的其它列是否存在交加,如图中的 (B,C) 和 (D):

  • 如果有交加,则后发动的 DeltaCommit 失败。
  • 如果没有交加,则两个工作持续后续的写入。


图 2 数据写入过程示意图

读取过程

接下来,介绍多流拼接场景下 Snapshot Query 的外围过程,即先对 LogFile 进行去重合并,而后再合并 BaseFile 和 去重后的 LogFile 中的数据。图 3 显示了整个数据合并的过程,具体能够拆分成以下 两个过程:

  • Merge LogFile
    Hudi 现有逻辑是将 LogFile 中的数据读出来寄存在 Map 中,对于 LogFile 中每条 Record,如果 Key 不存在 Map 中,则间接放入 Map,如果 Key 曾经存在于 Map 中,则须要更新操作。

在多流拼接中,因为 LogFile 中存在不同数据流写入的数据,即每条数据的列可能不雷同,所以在更新的时候须要判断雷同 Key 的两个 Record 是否来自同一个流,是则做更新,不是则做拼接。

如图 3 所示,读到 LogFile2 中的主键是 key1 的 Record 时,key1 对应的 Record 在 Map 中曾经存在,但这两个 Record 来自不同流,则须要拼接造成一条新的 Record (key1,b0_new,c0_new,d0_new) 放入 Map 中。

  • Merge BaseFile and LogFile

Hudi 现有默认逻辑是对于每一条存在于 BaseFile 中的 Record,查看 Map 中是否存在 key 雷同的 Record,如果存在,则用 Map 中的 Record 笼罩 BaseFile 中的 Record。在多流拼接中,Map 中的 Record 不会残缺笼罩 BaseFile 中对应的 Record,可能只会更新局部列的值,即 Map 中的 Record 对应的列。

如图 3 所示,以最简略的笼罩逻辑为例,当读到 BaseFile 中的主键是 key1 的 Record 时,发现 key1 在 Map 中曾经存在并且对应的 Record 有 BCD 三列的值,则更新 BaseFile 中的 BCD 列,失去新的 Record(key1,b0_new,c0_new,d0_new,e0),留神 E 列没有被更新,所以放弃原来的值 e0。
对于新增的 Key 如 Key3 对应的 Record,则须要将 BCE 三列补上默认值造成一条残缺的 Record。


图 3 SnapShot Query 中数据合并过程

异步 Compaction

为了晋升读取性能,某些数据源的写入工作会同步执行 Compaction,但实际过程中发现同步执行 Compaction 会阻塞写入工作,而且 Compaction 工作须要资源比拟多,可能会抢占流式导入工作的资源。

针对这类场景,通过独立的 Compaction Service 来隔离 Compaction 工作和流式数据导入工作。与 Hudi 自身自带的异步 Compaction 不同的是,用户无需指定要执行的 Compaction Instant,且有一个独立的 Compaction Service 负责所有的表的 Compaction 操作。对于 Compaction Service 的细节就不在本文开展,详情可参考 RFC-43。

具体过程是流式导入工作同步生成 Schedule Compaction Plan,并将 Plan 存入 Hudi MetaStore。有一个独立于流式导入工作的 Async Compactor,它从 Hudi MetaStore 循环拉取 Compaction Plan 并执行。

场景实际与将来布局

最终,基于 Hudi 多流拼接的计划,在实时数仓的 DWS 层落地,单表反对了 3+ 数据流的并发导入,笼罩了数百 TB 的数据。

此外,在应用 Spark 对宽表数据进行查问时,在单次扫描量几十 TB 的查问中,性能相比于间接应用多表关联性能晋升在 200% 以上,在一些更加简单的查问下,也有 40-140% 的性能晋升。

目前,基于 Hudi 多流拼接计划易用性有余,单个工作至多须要配置超过 10 个参数,为了进一步升高用户应用老本,后续会做局部列插入和更新的 SQL 的语法反对以及参数的收敛。

除此之外,为了进一步晋升宽表数据查问性能,还打算在多流拼接场景下反对基于列存格局的 LogFile,提供列裁剪和过滤条件下推等性能。

数据湖团队正在招人,
欢送关注 字节跳动数据平台 同名公众号

相干产品

  • 火山引擎湖仓一体剖析服务 LAS

面向湖仓一体架构的 Serverless 数据处理剖析服务,提供一站式的海量数据存储计算和交互剖析能力,齐全兼容 Spark、Presto、Flink 生态,帮忙企业轻松实现数据价值洞察。点击理解

  • 火山引擎 E -MapReduce

反对构建开源 Hadoop 生态的企业级大数据分析系统,齐全兼容开源,提供 Hadoop、Spark、Hive、Flink 集成和治理,帮忙用户轻松实现企业大数据平台的构建,升高运维门槛,疾速造成大数据分析能力。点击理解

退出移动版