Hudi、Iceberg 和 Delta Lake:数据湖表格式比较

2022-12-02 21:27:47 浏览数 (1)

介绍

在构建数据湖时,可能没有比存储数据格式更重要的决定了。结果将直接影响其性能、可用性和兼容性。

令人鼓舞的是,只需更改存储数据的格式,我们就可以解锁新功能并提高整个系统的性能。

Apache Hudi Apache IcebergDelta Lake是目前为数据湖设计的同类最佳格式。这三种格式都解决了数据湖中一些最紧迫的问题:

  1. 原子事务—— 保证对湖的更新或追加操作不会中途失败并使数据处于损坏状态。
  2. 一致的更新—— 防止读取失败或在写入期间返回不完整的结果。还处理潜在的并发写入冲突。
  3. 数据和元数据可扩展性—— 当表增长到数千个分区和数十亿个文件的大小时,避免对象存储 API 和相关元数据的瓶颈。

让我们仔细看看每种格式在更新性能、并发性和与其他工具的兼容性方面的方法。最后,我们将就哪种格式对您的数据湖最有意义提供建议。

平台兼容性

Hudi

Hudi 最初由Uber开源,旨在支持对列式数据格式的增量更新。它支持从多个来源摄取数据,主要是 Apache Spark 和 Apache Flink。它还提供了一个基于 Spark 的实用程序,用于从Apache Kafka等外部源读取数据。

支持从Apache Hive、Apache Impala和PrestoDB读取数据。还有一个专用工具可以将 Hudi 表模式同步到 Hive Metastore。

Iceberg

Iceberg最初由Netflix发布,旨在解决在 S3 上存储大型Hive 分区数据集时出现的性能、可扩展性和可管理性挑战。

Iceberg 支持 Apache Spark 的读写,包括 Spark 的结构化流。Trino (PrestoSQL) 也支持读取,但对删除的支持有限。Apache Flink支持读写。最后,Iceberg 提供了对Apache Hive的读取支持。

Delta Lake

Delta Lake 作为开源项目由 Databricks(Apache Spark 的创建者)维护,毫不奇怪地提供了与 Spark 的深度集成以进行读写。

使用 Hive 的SymlinkTextInputFormat可为Presto、AWS Athena、AWS Redshift Spectrum和Snowflake提供读取支持。尽管这需要为每个 Delta 表分区导出一个 symlink.txt 文件,并且您可能会怀疑,维护较大的表会变得昂贵。

更新性能和吞吐量

对大型不可变对象的行级更新的支持可以通过多种方式完成,每种方式在性能和吞吐量方面都有其独特的权衡。

让我们看看每种数据格式用于 UPSERT 操作的策略。我们还将涉及与读取性能相关的其他优化。

Hudi

Hudi 表在处理 UPSERTS 时提供的性能权衡是灵活的(且明确的)。两种不同类型的 Hudi 表之间的权衡不同:

  • Copy on Write Table  — 更新专门写入列式 parquet 文件,创建新对象。这增加了写入成本,但将读取放大降低到零,使其成为读取繁重工作负载的理想选择。
  • Merge on Read Table  — 更新立即写入基于行的日志文件,并定期合并到列式Parquet中。有趣的是,查询可以包含或不包含最新的日志文件数据,为用户在数据延迟和查询效率之间进行选择提供了一个有用的旋钮。

有关 Hudi 提供的可调性能权衡的更多信息,请参阅Hudi 编写的性能延迟。

Hudi 通过利用Key Indexing来有效跟踪哪些文件包含陈旧记录,从而进一步优化了压缩。

Iceberg

随着去年夏天 Spark 3.0 的发布,Iceberg 通过 MERGE INTO 查询支持 upserts。他们使用直接的写时复制方法工作,其中包含需要更新记录的文件会立即被重写。

Iceberg 擅长的地方在于包含大量分区的表的读取性能。通过维护将对象映射到分区并保留列级统计信息的清单文件,Iceberg 避免了昂贵的对象存储目录列表或从 Hive 获取分区数据的需要。

此外,Iceberg 的清单允许将单个文件同时分配给多个分区。这使得 Iceberg 表在分区修剪方面很有效,并改善了高度选择性查询的延迟。

Delta Lake

在 MERGE 操作期间,Delta 使用基于元数据的数据跳过将文件分类为需要插入、更新或删除的数据。然后它执行这些操作并将它们作为“提交”记录在一个名为Delta Log的 JSON 日志文件中。这些日志文件每 10 次提交被重写为 Parquet “检查点”文件,该文件保存表的整个状态,以防止代价高昂的日志文件遍历。

为了保持性能,Delta 表需要经历周期性的压缩过程,这些过程需要许多小 parquet 文件并将它们组合成更少、更大的文件(最佳约 1GB,但至少 128MB 大小)。Delta Engine是 Databricks 的专有版本,支持自动触发此过程的Auto-Compaction,以及其他幕后写入优化。

Delta 引擎通过提供使用 Bloom Filters的关键索引、 Z-Ordering以在读取时更好地进行文件修剪、本地缓存等,进一步提高了其开源引擎的性能。

并发保证

允许对数据表进行就地更新意味着处理并发。

如果有人在更新表格时读取表格会发生什么?当多个编写者同时进行相互冲突的更改时会发生什么?

通常,数据库通过多版本并发控制 ( MVCC ) 解决此问题,这是一种利用逻辑事务日志的方法,所有更改都附加在其中。

另一种称为乐观并发控制 ( OCC ) 的方法允许同时发生多个写入,仅在最终提交之前检查冲突。如果检测到冲突,则重试其中一个事务,直到成功。

Hudi

Hudi 确实提供了 MVCC 和 OCC 并发控制。

带有 Hudi 的 MVCC 意味着所有写入都必须在其中央日志中完全排序。为了提供这种保证,Hudi 将写入并发限制为 1,这意味着在给定时间点只能有一个写入者到表中。

为了防止这种限制,Hudi 现在还试验性地提供 OCC。此功能需要Apache Zookeeper或Hive Metastore来锁定单个文件并提供隔离。

Iceberg

Iceberg 表通过在更新期间对元数据文件执行原子交换操作来支持乐观并发 (OCC)。

它的工作方式是每次写入都会创建一个新表“快照”。然后,写入者尝试对保存当前快照 ID 的特殊值进行比较和交换( CAS ) 操作。如果在提交期间没有其他写入者替换快照,则操作成功。如果另一位作家同时进行提交,则另一位作家将不得不重试直到成功。

在 HDFS 等分布式文件系统上,这可以在本地完成。对于 S3,需要一个额外的组件来存储指针(目前仅支持Hive Metastore)。

Delta Lake

Delta文档解释说它使用 Optimistic Control 来处理并发,因为大多数数据湖操作将数据附加到按时间排序的分区并且不会发生冲突。

在两个进程将提交添加到 Delta 日志文件的情况下,Delta 将“静默无缝地”检查文件更改是否重叠,并在可能的情况下允许两者都成功。

但是,这意味着底层对象存储需要一种方法来提供 CAS 操作或当多个写入者开始覆盖彼此的日志条目时写入失败的方法。

与 Iceberg 类似,此功能可以在 HDFS 上开箱即用,但不受 S3 支持。因此, Delta on AWS不支持从多个 Spark 集群写入并具有真正的事务保证。

注意:专有的 Delta Engine 版本支持使用 Databricks 自身管理的外部同步服务器在 S3 上进行多集群写入。

那么哪一个适合你呢?

如果您已经做到了这一步,我们已经了解了 Apache Hudi、Delta Lake 和 Apache Iceberg 之间的一些重要相似点和不同点。

现在是决定哪种格式对您的用例最有意义的时候了!我的建议以最适用的场景为指导:

如果……请选择Iceberg

您的主要痛点不是对现有记录的更改,而是在对象存储(超过 10k 个分区)上管理大型表的元数据负担。采用 Iceberg 将缓解与 S3 对象列表或 Hive Metastore 分区枚举相关的性能问题。

相反,对删除和突变的支持仍处于初步阶段,并且存在与数据保留相关的操作开销。

如果…请使用Hudi

您使用各种查询引擎,并且需要灵活地管理变异数据集。请注意,支持工具和整体开发人员体验可能很粗糙。尽管可能,但安装和调整 Hudi 以应对真正的大规模生产工作负载也需要运营开销。

如果您使用的是 Athena、Glue 或 EMR 等 AWS 托管服务 - Hudi 已经预先安装和配置,并且受AWS 支持。

如果……请选择 Delta Lake

您主要是 Spark 商店,并期望写入吞吐量相对较低。如果您也已经是 Databricks 的客户,那么 Delta Engine 为读写性能和并发性带来了显着的改进,加倍关注他们的生态系统是有意义的。

对于其他 Apache Spark 发行版,重要的是要了解 Delta Lake 虽然是开源的,但很可能总是落后于 Delta Engine 以充当产品差异化因素。

原文链接:https://lakefs.io/hudi-iceberg-and-delta-lake-data-lake-table-formats-compared/

0 人点赞