字节跳动数据湖技术选型的思考

技术

点击上方👆蓝字关注我们!

picture.image

本文是字节跳动数据平台开发套件团队在 Flink Forward Asia 2021: Flink Forward 峰会上的演讲,着重分享了字节跳动数据湖技术上的选型思考和探索实践。

作者|Gary Li,字节跳动数据平台开发套件团队高级研发工程师,数据湖开源项目 Apache Hudi PMC Member

随着 Flink 社区的不断发展,越来越多的公司将 Flink 作为首选的大数据计算引擎。字节跳动也在持续探索 Flink,作为众多 Flink 用户中的一员,对于 Flink 的投入也是逐年增加。

字节跳动数据集成的现状

在 2018 年,我们基于 Flink 构造了异构数据源之间批式同步通道,主要用于将在线数据库导入到离线数仓,和不同数据源之间的批式传输。

在 2020 年,我们基于 Flink 构造了 MQ-Hive 的实时数据集成通道,主要用于将消息队列中的数据实时写入到 Hive 和 HDFS,在计算引擎上做到了流批统一。

到了 2021 年,我们基于 Flink 构造了实时数据湖集成通道,从而完成了湖仓一体的数据集成系统的构建。

picture.image

字节跳动数据集成系统目前支持了几十条不同的数据传输管道,涵盖了线上数据库,例如 MySQL、Oracle 和 MongoDB;消息队列,例如 Kafka、RocketMQ;大数据生态系统的各种组件,例如 HDFS、Hive 和 ClickHouse。

在字节跳动内部,数据集成系统服务了几乎所有的业务线,包括抖音、今日头条等大家耳熟能详的应用。

整个系统主要分成 3 种模式——批式集成、流式集成和增量集成。

  • 批式集成模式基于 Flink Batch 模式打造,将数据以批的形式在不同系统中传输,目前支持了 20 多种不同数据源类型。
  • 流式集成模式主要是从 MQ 将数据导入到 HiveHDFS ,任务的稳定性和实时性都受到了用户广泛的认可。
  • 增量模式即 CDC 模式 ,用于支持通过数据库变更日志 Binlog,将数据变更同步到外部组件的数据库。

这种模式目前支持 5 种数据源,虽然数据源不多,但是任务数量非常庞大,其中包含了很多核心链路,例如各个业务线的计费、结算等,对数据准确性要求非常高。

在 CDC 链路的整体链路比较长。首先,首次导入为批式导入,我们通过 Flink Batch 模式直连 MySQL 库拉取全量数据写入到 Hive,增量 Binlog 数据通过流式任务导入到 HDFS。

由于 Hive 不支持更新操作,我们依旧使用了一条基于 Spark 的批处理链路,通过 T-1 增量合并的方式,将前一天的 Hive 表和新增的 Binlog 进行合并从而产出当天的 Hive 表。

随着业务的快速发展,这条链路暴露出来的问题也越来越多。

  • 首先,这条基于 Spark 的离线链路资源消耗严重,每次产出新数据都会涉及到一次全量数据 Shuffle 以及一份全量数据落盘,中间所消耗的储存以及计算资源都比较严重。
  • 同时,随着字节跳动业务的快速发展,近实时分析的需求也越来越多。
  • 最后,整条链路流程太长,涉及到 Spark 和 Flink 两个计算引擎,以及 3 个不同的任务类型,用户使用成本和学习成本都比较高,并且带来了不小的运维成本。

为了解决这些问题,我们希望对增量模式做一次彻底的架构升级, 将增量模式合并到流式集成中,从而可以摆脱对 Spark 的依赖,在计算引擎层面做到统一

改造完成后,基于 Flink 的数据集成引擎就能同时支持批式、流式和增量模式,几乎可以覆盖所有的数据集成场景。

同时,在增量模式上,提供和流式通道相当的数据延迟,赋予用户近实时分析能力。在达到这些目标的同时,还可以进一步降低计算成本、提高效率。

picture.image

经过一番探索,我们关注到了正在兴起的数据湖技术。

关于数据湖技术选型的思考

我们的目光集中在了 Apache 软件基金会旗下的两款开源数据湖框架 IcebergHudi 中。

Iceberg 和 Hudi 两款数据湖框架都非常优秀。但两个项目被创建的目的是为了解决不同的问题,所以在功能上的侧重点也有所不同。

  • Iceberg :核心抽象对接新的计算引擎的成本比较低,并且提供先进的查询优化功能和完全的 schema 变更。
  • Hudi :更注重于高效率的 Upsert 和近实时更新,提供了 Merge On Read 文件格式,以及便于搭建增量 ETL 管道的增量查询功能。

一番对比下来,两个框架各有千秋,并且离我们想象中的数据湖最终形态都有一定距离,于是我们的核心问题便集中在了以下两个问题:

  • 哪个框架可以更好的支持我们 CDC 数据处理的核心诉求?
  • 哪个框架可以更快速补齐另一个框架的功能,从而成长为一个通用并且成熟的数据湖框架?

经过多次的内部讨论,我们认为: Hudi 在处理 CDC 数据上更为成熟 ,并且社区迭代速度非常快,特别是最近一年补齐了很多重要的功能,与 Flink 的集成也愈发成熟,最终我们选择了 Hudi 作为我们的数据湖底座。

索引系统

我们选择 Hudi, 最为看重的就是 Hudi 的索引系统

picture.image

这张图是一个有索引和没有索引的对比。

在 CDC 数据写入的过程中,为了让新增的 Update 数据作用在底表上,我们需要明确知道这条数据是否出现过、出现在哪里,从而把数据写到正确的地方。在合并的时候,我们就可以只合并单个文件,而不需要去管全局数据。

如果没有索引,合并的操作只能通过合并全局数据,带来的就是全局的 shuffle。

在图中的例子中,没有索引的合并开销是有索引的两倍,并且如果随着底表数据量的增大,这个性能差距会呈指数型上升。

所以,在字节跳动的业务数据量级下,索引带来的性能收益是非常巨大的。

Hudi 提供了多种索引来适配不同的场景,每种索引都有不同的优缺点,索引的选择需要根据具体的数据分布来进行取舍,从而达到写入和查询的最优解。

下面举两个不同场景的例子。

日志数据去重场景

在日志数据去重的场景中,数据通常会有一个 create_time 的时间戳,底表的分布也是按照这个时间戳进行分区,最近几小时或者几天的数据会有比较频繁的更新,但是更老的数据则不会有太多的变化。

冷热分区的场景就比较适合布隆索引、带 TTL 的 State 索引和哈希索引

CDC 场景

第二个例子是一个数据库导出的例子,也就是 CDC 场景。这个场景更新数据会随机分布,没有什么规律可言,并且底表的数据量会比较大,新增的数据量通常相比底表会比较小。

在这种场景下,我们可以 选用哈希索引、State 索引和 HBase 索引来做到高效率的全局索引

这两个例子说明了不同场景下,索引的选择也会决定了整个表读写性能。Hudi 提供多种开箱即用的索引,已经覆盖了绝大部分场景,用户使用成本非常低。

Merge On Read 表格式

除了索引系统之外,Hudi 的 Merge On Read 表格式也是一个我们看重的核心功能之一。这种表格式让实时写入、近实时查询成为了可能。

在大数据体系的建设中,写入引擎和查询引擎存在着天然的冲突:

  • 写入引擎更倾向于写小文件,以行存的数据格式写入,尽可能避免在写入过程中有过多的计算包袱,最好是来一条写一条。
  • 查询引擎则更倾向于读大文件,以列存的文件格式储存数据,比如说 parquet 和 orc,数据以某种规则严格分布,比如根据某个常用字段进行排序,从而做到可以在查询的时候,跳过扫描无用的数据,来减少计算开销。

为了在这种天然的冲突下找到最佳的取舍,Hudi 支持了 Merge On Read 的文件格式。

picture.image

MOR 格式中包含两种文件:一种是基于行存 Avro 格式的 log 文件,一种是基于列存格式的 base 文件,包括 Parquet 或者 ORC。

log 文件通常体积较小,包含了新增的更新数据。base 文件体积较大,包含了所有的历史数据。

写入引擎可以低延迟的将更新的数据写入到 log 文件中。

查询引擎在读的时候将 log 文件与 base文 件进行合并,从而可以读到最新的视图;compaction 任务定时触发合并 base 文件和 log 文件,避免 log 文件持续膨胀。在这个机制下,Merge On Read 文件格式做到了实时写入和近实时查询。

增量计算

索引系统Merge On Read 格式 给实时数据湖打下了非常坚实的基础, 增量计算 则是这个基础之上的 Hudi 的又一个亮眼功能:

增量计算赋予了 Hudi 类似于消息队列的能力。用户可以通过类似于 offset 的时间戳,在 Hudi 的时间线上拉取一段时间内的新增数据。

在一些数据延迟容忍度在分钟级别的场景中,基于 Hudi 可以统一 Lambda 架构,同时服务于实时场景和离线场景,在储存上做到流批一体。

结语

在选择了基于 Hudi 的数据湖框架后,我们基于字节跳动内部的场景,打造定制化落地方案。我们的目标是通过 Hudi 来支持所有带 Update 的数据链路。

数据湖集成技术已经通过 火山引擎大数据研发治理套件 DataLeap 对外开放,点击【

阅读原文

】了解产品。

picture.image

19
0
0
0
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论