Apache Hudi特性—表类型

下面将讨论一些关键概念和术语,这些概念和术语对于理解和有效使用这些原语非常重要。

表类型

Hudi表类型定义了如何在DFS上索引和布局数据,以及如何在这样的组织上实现上述原语和时间轴活动(即如何写入数据)。

Hudi支持如下的表类型:

  • (1) Copy On Write:仅使用柱状文件格式存储数据(例如parquet)。通过在写入过程中执行同步合并,简单地更新版本和重写文件。
  • (2) Merge On Read:使用柱状(如parquet) + 基于行(如avro)的文件格式组合存储数据。更新被记录到增量文件中,随后压缩,以同步或异步的方式生成柱状文件的新版本。

这两种表类型之间的对比见下表。

  Copy On Write Merge On Read
数据延迟 较高 较低
查询延迟 较低 较高
更新成本(I / O) 较高(重写整个parquet) 较低(追加到增量日志文件)
Parquet文件大小 较小(高更新(I/O)成本) 较高(低更新(I/O)成本)
写入放大 较高 较低(取决于压缩策略)

1. Copy On Write表

Copy-On-Write表中的文件片只包含base/columnar文件(即基本文件和柱状文件),每次提交都会生成基本文件的新版本。换句话说,我们隐式地压缩每个提交,这样只存在列数据。因此,写放大(输入数据的1字节所写入的字节数)要高得多,其中读放大为零。这是分析工作负载非常需要的属性,因为分析工作负载主要是读密集型的。

当数据写入到“copy-on-write”表并在其上运行两个查询时,它在概念上的工作原理如下图所示。

当写入数据时,对现有文件组的更新会为该文件组生成一个新片,并在该片上标记上提交瞬态时间(instant time),而insert则分配一个新的文件组,并为该文件组写入它的第一个片。这些文件切片和它们的提交瞬态时间(instant time)在上图中是用颜色编码的。对这样一个表运行的SQL查询(例如:select count(*)计算该分区中的总记录),首先检查最近提交的时间轴,并过滤每个文件组的所有文件片(除了最新的文件片)。如图12-3中所见,一个旧的查询不会看到的当前正在提交的文件(用粉红色编码),但是一个新的查询会在提交后开始获得新数据。因此,查询不受任何写失败/部分写的影响,只在已提交的数据上运行。

Copy-On-Write表的目的是为了从根本上改善当前对表的管理方式:

  • (1) 第一类支持在文件级自动更新数据,而不是重写整个表/分区。
  • (2) 能够增量地使用变更,而不是浪费的扫描或摸索启发式。
  • (3) 严格控制文件大小以保持优异的查询性能(小文件会严重影响查询性能)。

2. Merge On Read表

Merge-On-Read表是copy-on-write表的超集,在某种意义上,它仍然支持读优化查询,只暴露最新的文件片中的base/columnar文件。此外,它将每个文件组的传入upsert存储到基于行的增量日志上,以便在查询期间动态地将增量日志应用到每个文件ID的最新版本上,从而支持快照查询。因此,这种表类型试图智能地平衡读和写放大,以提供近实时的数据。这里最重要的变化是压缩器,它现在小心地选择哪些增量日志文件需要压缩到它们的柱状基文件中,以检查查询性能(更大的增量日志文件将导致在查询侧合并数据更长的合并时间)。

Merge-On-Read表的工作原理,以及两种查询类型—快照查询和读取优化查询的展示,如下图所示。

在这个例子中发生了许多有趣的事情,这些事情揭示了这种方法的微妙之处:

  • (1) 现在大约每1分钟提交一次,这是其他表类型无法做到的。
  • (2) 在每个文件ID组中,现在都有一个增量日志文件,它保存对基本柱状文件中的记录的传入更新。在这个示例中,增量日志文件保存了从10:05到10:10的所有数据。与前面一样,基本柱状文件仍然使用提交进行版本控制。因此,如果只看基文件,那么表布局看起来就像写表(copy-on-write)。
  • (3) 定期压缩过程协调来自增量日志的这些更改,并生成一个新版本的基文件,就像示例中的10:05所发生的那样。
  • (4) 查询同一个底层表有两种方式:读取优化查询和快照查询,这取决于我们选择的是查询数据的性能还是新鲜度。
  • (5) 对于读优化查询,提交的数据何时可用于查询的语义发生了微妙的变化。注意,这样一个在10:10运行的查询不会看到10:05之后的数据,而快照查询总是看到最新的数据。
  • (6) 什么时候触发压缩以及压缩什么是解决这些难题的关键。通过实施压缩策略,我们积极地压缩最新的分区,而不是旧的分区,我们可以确保读取优化查询在X分钟内以一致的方式看到发布的数据。

在读表上进行合并的目的是直接在DFS之上支持近实时的处理,而不是将数据复制到可能无法处理数据量的专门系统。这个表还有一些次要方面的好处,比如通过避免同步合并数据来减少写放大(也就是一批中每1个字节的数据写入的数据量)。


《PySpark原理深入与编程实战》