在基于 Lakehouse 架构的平台中,存储层在高效持久化各种数据和提升查询性能方面起着重要作用。Lakehouse 存储层由云存储、文件格式和表格式组成。本章将重点介绍这些概念以及实现 Lakehouse 存储层的可用技术。
我将解释与 Lakehouse 存储相关的基本概念,行存储和列存储之间的区别,以及存储如何与性能密切相关。然后,我们将深入探讨用于存储分析用例数据的文件格式,使用每种格式的好处,以及在构建数据平台时应考虑的关键特性。
一旦您理解了这些概念,我们将更容易讨论本章的核心主题——开放表格式。我们将讨论主要的表格式、它们的特性和优点,以及在做出设计决策时应牢记的具体限制。
在本章的最后一部分,我将讨论选择合适表格式的关键设计考虑因素。这将帮助您在日常项目中做出更好的设计决策。
Lakehouse 存储:关键概念
存储层是数据生态系统的支柱。当您实现一个数据平台时,您需要一个持久、可靠且高度可用的存储层,它能够持久化各种类型的大量历史数据。Lakehouse 平台需要一个存储层,不仅可以实现快速检索,还支持 ACID 特性,并保留数据的旧版本。
在深入探讨存储层及其组件的具体细节之前,我们先讨论两个在讨论文件和表格式时经常提到的重要概念:行存储与列存储,以及基于存储的性能。
行存储与列存储
每当您创建一个表或向表中插入记录时,数据会在底层存储硬件和磁盘上物理地存储为数据文件。现代数据平台使用云存储来持久化数据。有两种存储数据的方法:
- 行存储方法
- 列存储方法
表 3-1 显示了一个示例产品表。我们以这个表为例来理解这两种方法。
表 3-1. 示例产品表
| product_id | product_name | product_category |
|---|---|---|
| 22 | keyboard | computer accessory |
| 12 | headphone | computer accessory |
| 3 | mobile case | computer accessory |
在行存储方法中,数据按行存储在物理磁盘上。表 3-2 显示了使用行存储方法存储产品数据的方式。
表 3-2. 行存储
| 22 | keyboard | computer accessory | 12 | headphone | computer accessory | 3 | mobile case | computer accessory |
当您执行选择查询以检索数据时,它会从磁盘中读取完整的行。这在查询需要读取所有列的数据时是有利的。然而,分析工作负载通常只需要读取少数几列作为聚合或汇总。由于行存储的特性,查询必须读取所有记录的所有列,而不管查询需要多少列。
在列存储格式中,数据按列存储在物理存储中。表 3-3 显示了基于列存储的数据存储方式(与前面示例中的产品表相同)。
表 3-3. 列存储
| 22 | 12 | 3 | keyboard | headphone | mobile case | computer accessory | computer accessory | computer accessory |
对于分析查询,列存储有助于通过仅扫描存储这些列的磁盘块来快速检索数据。与行存储不同,查询不必为了几列特定的列而扫描完整记录。这种方法使得数据检索更快,尤其是在表中有数百个属性而查询只需要几列的情况下。此外,由于相同列的数据存储在一起,更容易对相同数据类型进行压缩,从而减少总体文件大小。
基于存储的性能优化
存储不仅仅是数据的持久化。它还通过减少要扫描的数据来使计算引擎更快地检索所需结果。性能不仅取决于计算引擎,还取决于底层存储。
任何分析查询的数据检索时间都会受到扫描数据量的严重影响。扫描的数据越少,获取结果的时间就越短。一些文件和表格式(将在本章后面讨论)有助于最小化查询需要扫描的数据量。最小化数据的过程也称为数据跳过或行跳过。
跳过不需要的数据有不同的方法,包括:
- 分区或文件修剪,这有助于减少查询需要扫描的分区或文件数量
- 索引和聚类,这有助于仅获取查询所需的确切记录,而不是扫描整个表
- 维护列级统计信息(如每列的最小值和最大值),这有助于仅扫描包含所需记录的相关数据块
不同的文件和表格式使用这些技术来减少数据扫描并快速检索结果。与其增加计算能力来提高查询性能,不如首先通过考虑以下方法来仅获取相关数据:
- 选择所需的属性
- 对表进行分区或聚类
- 维护列统计信息
- 其他类似的数据跳过方法
现在您了解了这些关键存储概念,让我们讨论用于实现 Lakehouse 存储的技术和组件。
Lakehouse 存储组件
Lakehouse 存储层由三个主要组件组成:
- 用于存储数据的云对象存储
- 用于压缩数据并支持分布式处理的开放文件格式
- 提供事务能力和高效数据检索的开放表格式
首先,我们来看一下云对象存储,它提供了存储能力。
云对象存储
存储层负责在 Lakehouse 架构中持久化所有数据。云存储最适合存储性质、类型、大小和接收速度各异的大量数据。
图 3-1 显示了 Lakehouse 存储层及其可用的不同云技术。
存储特性
用于实现物理存储的技术应具备以下基本特性:
持久性
存储应具有高度的持久性,能够根据系统的需要持久化数据。底层技术应确保数据不会被破坏,并采取措施避免任何数据丢失。
可用性
数据应始终可供消费者在需要时使用。即使在提供存储的服务出现停机期间,也应有足够的备份以向消费者提供所需数据。
可扩展性
数据存储服务应易于扩展,能够根据数据增长需求进行扩展,而无需人工干预。
成本
存储应具有较低的成本(相对于专用存储如数据仓库),并且应提供通过在热存储和冷存储层之间移动数据来优化成本的手段。
安全性
存储层的一个重要特性是提供内置的安全性。它应提供保护存储层中静态数据的功能。
大多数云存储如 Amazon S3、ADLS Gen2(本书中简称为 ADLS)和 GCS 都提供了所有这些内置功能,是实现 Lakehouse 平台的首选。HDFS 也可以用于实现存储层,但正如第一章所讨论的那样,我们将在本书中将讨论范围限制在云技术,因为它们最适合构建现代数据平台。
文件格式
存储层中的下一个组件是文件格式。文件格式定义了在云存储上存储数据的方法。数据是采用行存储方法还是列存储方法进行存储。现代文件格式提供了用于数据压缩的不同编码方案,并能够拆分数据文件以支持分布式处理。
组织一直在使用许多流行的文件格式来存储和交换数据,包括 CSV、JSON 和 XML。然而,这些文件格式在处理大数据方面存在一些关键限制:
- 它们的压缩能力有限,因此占用更多的存储空间。
- 数据检索时间显著较长,分析查询通常需要很长时间才能获取所需结果。
- 数据扫描不限于所需列;查询通常会扫描整行以处理结果。
- 一些文件格式没有内置模式,必须在读取这些文件时显式定义。
- 它们需要以未压缩的原始形式支持拆分以进行分布式处理。
什么是可拆分文件格式?
在分布式处理过程中,数据分布在各个集群中以支持并行处理。当文件存储在这些分布式存储上时,需要将其存储到各个数据块或块中,以便多个进程可以读取这些块。用于存储数据的文件格式应支持将文件拆分为多个块。大数据系统中的文件通常具有大容量并被压缩以节省存储空间并提高性能。它们应在压缩形式下可拆分以进行分布式处理。当使用 Snappy、LZO、bzip2 等算法进行压缩时,大数据文件格式支持这种拆分。然而,传统格式如 CSV 在使用 GZIP 压缩时不能被拆分。
为了存储和处理大量大数据,您需要具有良好压缩比、优化数据检索和数据跳过功能的开放文件格式。鉴于上述限制,各组织和产品供应商如 Cloudera 和 Hortonworks 引入了专用文件格式,以处理 Hadoop 生态系统中的大数据工作负载。这些格式即使在使用云技术构建的现代平台中也被广泛采用。
本节将讨论这些文件格式,它们的优点和限制。最流行的三种开放文件格式是:
- Apache Parquet
- Apache ORC
- Apache Avro
图 3-2 显示了用于实现文件格式组件的技术。Parquet、Avro 和 ORC 是基于 Apache 软件基金会(ASF)生态系统中开放技术的开放文件格式。
Parquet
Parquet 于 2013 年创建,已被许多组织采用用于大数据工作负载。它是一种使用列式存储来高效存储和检索数据的开源文件格式。与 CSV 和 JSON 文件格式相比,Parquet 提供了更好的压缩比,并在处理复杂数据时表现出色。
文件布局
图 3-3 显示了基于 ASF 文档的 Parquet 文件格式简化版本。
Parquet 文件结构如下:
- 每个 Parquet 文件由头部、尾部和数据块组成。
- 头部包含的细节指示该文件为 Parquet 格式。
- 数据块由多个行组构成,这些行组在文件中逻辑上合并了各个行。
- 行组由文件中存在的列组成。
- 每个列中的值以页面形式存储。
- 页面是 Parquet 中最细粒度的数据元素。
- 文件尾部包含行组和列的元数据。
- 元数据包括最小值/最大值等统计信息。
- 计算引擎使用尾部的最小值/最大值进行数据跳过。
关键特性
与 TXT、CSV 和 JSON 等文件格式相比,Parquet 提供了若干特性:
- 它在存储数据时施加的压缩根据其对列式数据存储的编码技术显著减小了文件大小(见本节末尾关于编码的注释)。
- Parquet 作为列式存储,可以仅检索所需的列,而不是扫描磁盘上存储的所有列。这有助于提高分析查询的性能,这类查询通常只需要少数几列进行聚合。
- Parquet 文件包含记录的架构信息,有助于在表中轻松加载数据,并使用如 Apache Spark 等框架分割文件进行分布式处理。
大多数构建本地或基于云的数据平台的组织将 Parquet 作为其主要数据格式。它是 Spark 的默认格式,Spark 是最广泛采用的大数据工作负载处理框架。Parquet 也已成为如 Microsoft Fabric (OneLake) 和 Databricks (Delta Lake) 等领先供应商平台的首选。
注释
像 Parquet 这样的开放文件格式会在将数据存储到磁盘之前将数据转换为二进制形式。这种二进制转换称为编码,并且可以通过与其原始、可读形式相比显著压缩数据。有多种编码技术,包括 Plain、Dictionary、Bit Packing 和 Run Length Encoding (RLE),这些技术单独或组合使用,用于压缩数据并支持更快的检索。
ORC(优化行列式文件格式)
ORC(Optimized Row Columnar),类似于 Parquet,也是一种列式文件格式,是 Apache Hive 标准 RCFile 格式的后继产品。ORC 提供 ACID 支持,具有内置索引以加快数据检索速度,并支持复杂数据类型,如结构体、列表和映射。
文件布局
图 3-4 展示了基于 ASF 文档的 ORC 文件格式的简化版本。
ORC 文件格式如下:
- 每个 ORC 文件包含头部、尾部和多个被称为条带的数据块。
- 头部有详细信息表明该文件是 ORC 格式。
- 每个条带包括索引数据、行数据和条带尾部。
- 索引数据持有存储数据的索引,并存储行组的最小值和最大值。
- 行数据持有扫描中使用的实际数据。
- 条带尾部包含每列的详细信息,包括编码、位置、最小值和最大值。
- 文件尾部包含与文件中的条带相关的统计数据、每个条带的行数和其他有助于跳过数据的信息。
注释
ORC 有三级索引:
- 文件级索引用于存储整个文件的列统计数据。
- 条带级索引用于存储每个条带的列统计数据。
- 行级索引用于存储条带中每组 10,000 行的列统计数据。
- 文件和条带级的列统计数据存储在文件尾部(与 Parquet 类似),以便在扫描时跳过文件的其余部分。
关键特性
与 CSV、JSON 和 TXT 文件相比,ORC 提供了若干特性和优势:
- ORC 与 Hive 有着深入的整合。它最初被创建为用于存储在 Hadoop 中的数据的文件格式,这些数据将使用 Hive 进行处理。 由于 ORC 是列式文件格式,它提供比 CSV 和 JSON 更好的压缩比率。
- ORC 是唯一一个使 Hive 能够为事务处理提供 ACID 特性的文件格式。
- ORC 主要用于广泛使用 Hive 处理数据的 Hadoop 生态系统中。大多数使用 Hortonworks Data Platform (HDP) 实施其数据生态系统的组织都采用 ORC 作为其主要格式。
Avro
Avro 是一种开源的、基于行的数据序列化格式,用于创建 Avro 数据文件。Avro 是 Hadoop 生态系统中最受欢迎的格式之一。组织在现代数据平台中广泛使用 Avro 来持久化大量原始数据,以便进行进一步的 ETL 处理。
文件布局
图 3-5 根据 ASF Avro 文档显示了 Avro 文件格式的简化版本。
一个 Avro 文件由一个头部和一个或多个数据块组成。头部包括文件元数据,包括模式、压缩代码的名称以及一个随机生成的同步标记,这有助于文件的分割。每个数据块包括以下内容:
- 该块中的对象数量
- 该块的大小(压缩后)
- 以其压缩形式序列化存储的数据
- 文件的 16 位同步标记
这种布局有助于高效地提取或跳过数据,同时检测任何损坏的块。
关键特性
像 Parquet 和 ORC 一样,Avro 也提供了一些独特的特性,帮助存储和处理大量数据:
-
其自描述的特性意味着它将模式与数据一起存储,任何读取器在读取数据时都可以访问模式。
-
模式以 JSON 或 Avro IDL(AVDL)格式存储,使其具有可读性,而实际数据则以二进制形式存储,以获得更好的压缩比。
-
Avro 支持模式演变,使其成为实现类似 ETL 的工作负载以适应模式更改的绝佳选择。
-
Avro 文件是可分割的,这意味着即使在压缩形式下也可以用于分布式处理,从而有助于更快的数据处理。 它支持多种语言,包括 JAVA、C、C++、C# 和 Python。
Avro 最适合实现诸如处理大数据的 ETL 管道以及需要支持处理模式更改的系统的用例。
相似点、差异和用例
所有这些文件格式的目标都是有效地存储数据并在读取数据时提高查询性能。这三者都有类似的特性,可以帮助实现这些目标;然而,它们在存储和压缩数据的方法上有关键的差异。
以下是它们的相似点和差异的总结,这将帮助您根据您的用例进行比较和选择:
支持的数据格式
这三种格式都支持存储大量的结构化和非结构化数据。组织广泛地用这些格式实施了基于 Hadoop 的数据平台。
压缩
这三种文件格式提供的压缩比 CSV、TXT 和 JSON 文件更高。这有助于减少存储容量并提高查询性能。与 Avro 文件格式相比,Parquet 和 ORC 提供了更好的压缩。
图 3-6 显示了这些文件格式为 2 GB 未压缩的 CSV 文件提供的压缩比的快速比较。
与未压缩的 CSV 文件相比,ORC 和 Parquet 提供了大约 70-75% 的压缩率,而 Avro 提供了大约 55-60% 的压缩率。这些与未压缩的 CSV 文件进行比较,因为压缩的 CSV 文件是不可分割的。
注释 我使用 Amazon EMR Spark 创建了用于此比较的输出文件,并且没有更改任何默认设置。在上述比较中,Parquet 和 ORC 文件大小是在 Snappy 压缩后的。
可分割性
Parquet、ORC 和 Avro 都是可分割的,并且可以在不解压数据的情况下支持分布式处理,这导致数据扫描次数减少和数据检索速度加快。
采用和用例
这三种文件格式广泛用于实施大数据工作负载:
Parquet 在各个组织中被广泛使用,并且可以说是三种格式中最受欢迎的。它与 Spark(最流行的处理框架之一)易于集成。
ORC 与 Hive 有深度集成,是唯一支持具有 ACID 特性的 Hive 的格式。
Avro 非常适用于 ETL 工作负载,其中更改模式是常见情况。
由于是列式的,Parquet 和 ORC 更适合只检索少数几列的分析工作负载。
文件格式布局
Parquet 和 ORC 遵循列式格式存储数据,但在实施方式上有所不同。Parquet 将数据存储为页面,而 ORC 将数据存储为条带。Avro 遵循基于行的方法,并将数据存储在块中。这些不同的方法影响它们的压缩比和数据跳过能力。
数据扫描
与 Parquet 和 ORC 相比,Avro 在写操作时性能更佳。当读取用于分析目的的列的子集时,Parquet 和 ORC 表现更好,因为它们可以基于列值跳过数据。
图 3-7 显示了从使用这些文件格式创建的表中检索单个列时扫描的数据量。
请注意,运行在使用 CSV 和 Avro 格式创建的表上的查询扫描了完整的数据,而使用 ORC 和 Parquet 格式的表扫描的数据要少得多(对应于单个列),因为它们使用的是列式格式。
模式演变
Avro 支持模式演变——可以添加或修改列。Parquet 和 ORC 仅支持在末尾(最后一列之后)添加列。
表格式
在第一章中,您了解了支持具有数据仓库类功能的数据湖的开放表格式。表格式有助于组织每个表的数据文件。它包含与数据文件相关的信息,如模式详情、文件创建和更新时间、每个文件中的记录数量以及记录级操作类型(添加和删除)。表格式为数据湖提供了 ACID 特性、更新和删除的支持以及数据跳过能力,从而提高了查询性能。
在本节中,我们将深入了解这些开放表格式,以理解它们的架构和特性。然而,在我们讨论现代表格式之前,让我们先了解一下 Hive,它是传统 Hadoop 生态系统中使用的较早一代表格式。
Hive
随着 Hadoop 技术的兴起,数据湖开始流行,这些技术将 HDFS 作为主要存储。Hive 提供了在 HDFS 数据上执行分析工作负载的结构和能力。它是在 Hadoop 集群内构建数据仓库系统最受欢迎和广泛采用的技术之一。
Hive 的关键组件包括 HiveServer2(HS2)、Hive Metastore(HMS)和 Beeline(Hive 的 CLI),它们是其服务的一部分。它使用 HDFS 存储数据并使用 MapReduce 处理数据。本节将重点介绍 Hive 作为表格式如何存储和读取数据。
注意
Hive 有一个称为 Hive Metastore(HMS)的中央元数据存储库,用于存储 Hive 表的模式详情。它还存储与每个表的分区相关的信息。许多现代目录工具,如 AWS Glue 和 Databricks,使用 HMS 存储元数据。我们将在第四章更详细地讨论元存储和目录。
与其他传统数据仓库不同,您无需将数据加载到 Hive 仓库中。数据位于数据湖存储(HDFS、云对象存储)内,Hive 在这个数据湖存储之上提供元数据层。这个元数据层提供了 Hive 表的模式。
图 3-8 显示了 Hive 表目录结构。
当您在 Hive 中创建表时,它将数据存储在 HDFS 中,将模式存储在 HMS 中。Hive 表目录在其根表文件夹下包含所有文件。如果您对此表进行分区,它将创建额外的分区级目录,并将相关数据文件放置在这些目录下。
数据始终驻留在数据湖中(在本例中为 HDFS),并且不会加载到任何其他专用仓库存储中,从而使用户能够仅使用单一存储层构建类似湖仓的系统。Hive 的一些关键功能包括:
分区
Hive 支持对表进行分区,这有助于优化查询,只扫描所需的分区而不是完整表。
支持的文件格式
Hive 支持多种文件格式存储数据,包括 CSV、JSON、Parquet、ORC 和 Avro,这增加了其灵活性。
支持多个引擎
您可以通过多个计算引擎访问 HMS,包括 Spark、Presto 和其他商业查询引擎。
然而,Hive 也有一些局限性,这些局限性影响了现代表格式的演化。一些限制了 Hive 作为湖仓表格式使用的局限性包括:
没有 ACID
支持 Hive 没有开箱即用的 ACID 功能,这导致数据不一致。Hive 使用 ORC 文件格式提供有限的 ACID 支持;然而,像 Parquet 和 Avro 这样的格式没有 ACID 支持,这可能导致数据损坏和并发问题。
性能有限
查询规划通常需要更长时间,因为 Hive 不维护数据的版本或快照。Hive 必须列出目录中的所有文件,以确定检索数据所需的文件,这增加了较大表的总体性能开销。
不支持更新和删除操作
您不能直接通过执行 SQL 命令更新或删除 Hive 表中的任何记录。由于数据驻留在 HDFS 上,而 HDFS 是不可变的,因此没有直接更新或删除记录的方法。如果您想修改一些记录,您必须首先识别它们所在的分区,删除所有这些分区,并重新创建分区,包括修改的和原始未受影响的记录。这导致更长的处理时间以及大量数据的不必要删除和重新创建。
所有这些局限性促成了现代开放表格式的演化,组织已逐渐转向这些格式以实施其数据生态系统。
图 3-9 显示了三种流行的开放表格式——Apache Iceberg、Apache Hudi 和 Delta Lake——用于实施湖仓架构。
正如我们之前讨论的,数据以数据文件的形式存储在云存储中。表格式在这些数据文件之上提供了一个额外的事务层。
现在让我们来看看您可以考虑在数据平台中实施的三种流行的开放表格式。
Iceberg
Iceberg 起源于 Netflix,是一种广泛采用的开放表格式——被像 Apple、Netflix 和 Airbnb 这样的组织使用,并得到了包括 Dremio、Snowflake 和 Tabular 在内的各种供应商平台的支持。由于其丰富的功能集和支持 Parquet、ORC 和 Avro 文件格式的能力,它最近变得越来越受欢迎。
表格布局
图 3-10 根据 Apache Iceberg 规范显示了 Iceberg 的布局。Iceberg 由两个主要部分组成:元数据层和数据层。
Iceberg 的目录结构如下:
Iceberg 目录
Iceberg 目录提供表位置并指向最新的元数据文件。
元数据层
元数据层包含多个元素:
-
像 Hive 元数据存储一样,Iceberg 在元数据文件中存储模式详情和分区信息。
-
元数据文件中有一个称为“快照”的部分。每个快照指向一个称为“清单列表”的文件。对于每个新事务,都会在元数据文件中添加一个新快照。
-
清单列表指向属于特定快照的所有清单文件。
-
这些清单文件存储数据文件列表和列统计信息的详细信息。
-
数据层 Iceberg 支持 Parquet、ORC 和 Avro 文件格式,用于写入数据文件。
关键特性
现在您已了解 Iceberg 的基本结构,让我们讨论其特性和优点:
ACID 支持
ACID 支持是使用湖仓架构构建的平台的最重要特性之一。Iceberg 支持 ACID 属性,并为并发读写提供一致性和隔离。
模式演变
Iceberg 支持模式演变,有助于适应源系统的模式更改,以确保在存储数据时不会丢失数据。
隐藏分区
在早期的表格式中,如 Hive,要有效使用分区,你必须在过滤谓词中使用分区列。不可能对这些分区列进行任何转换。例如,当你只在过滤条件中使用“月份”时,一个按“日期”(YYYYMMDD)分区的表不能限制到特定月份的数据扫描。Iceberg 提供了一种称为隐藏分区的功能。这些帮助您对分区列进行转换,并根据分区转换限制扫描。
分区演变
随着时间的推移,数据量增加,现有分区可能需要更改以提高查询性能。在这种情况下,Hive 中唯一的选项是根据新的分区重写表。Iceberg 提供了一种功能,无需重写数据即可演变这些分区。
时光旅行
时光旅行有助于查询历史数据和查看已更新或删除的记录的以前版本。
支持的文件格式
在撰写本书时,Iceberg 是唯一支持所有三种文件格式——Parquet、ORC 和 Avro——用于存储数据的格式。
这些只是 Iceberg 提供的一些重要特性。如果您计划使用 Iceberg 作为实施湖仓平台的表格式,您可以参考 Tomer Shiran、Jason Hughes 和 Alex Merced(O’Reilly)的《Apache Iceberg: The Definitive Guide》来深入了解这个主题。
Hudi
Hudi(代表 Hadoop Upserts Deletes and Incrementals)是一个流式数据湖平台,为数据湖带来数据仓库的能力。它可以执行记录级别的插入更新(upserts)和删除,并支持增量数据处理。Hudi 最初由 Uber 创建,旨在提供一个高效的增量数据处理框架,后来成为 Apache 基金会的开源项目。
Hudi 的整体技术栈远不止一个表格式。在本节中,我们将重点介绍你可以用来实施现代数据平台的 Hudi 表格式的特性。
表格布局
图 3-11 根据官方 Apache Hudi 文档展示了基于 Hudi 的数据布局。
元数据层
Hudi 在 .hoodie 目录中存储事务日志。表的元数据存储在 .hoodie 目录下的元数据目录中。Hudi 还创建了一个 hoodie.properties 文件来保存表级配置。表的写入者和读取者使用这个配置文件。
数据层
基于用于表分区的列,会在基路径下为不同的列值创建子目录以存储数据文件。Hudi 将这些数据文件存储为基础文件或日志文件。
让我们看看构成 Hudi 数据管理框架的各种目录和文件。
关键特性
Hudi 提供多个功能,有助于实现湖仓平台:
**支持 ACID、更新和删除 **
Hudi 为数据湖提供 ACID 事务保证,并提供写入者和读取者查询之间的隔离。它还允许用户执行记录级别的插入更新和删除。
时光旅行
您可以使用 Hudi 提供的时光旅行功能查询数据的先前状态。这个功能可以帮助您轻松地回退到表的旧版本,调试更改并维护审计历史。
性能优化
Hudi 提供多种性能优化功能,包括:
-
聚集,帮助将数据彼此靠近
-
索引,使插入更新和删除更高效
-
压缩,帮助执行低延迟摄取和更快的读取
提交时间线
Hudi 维护了表上所有提交的时间线,每个事务创建的文件信息作为其一部分。增量查询使用这些提交来获取插入和在特定提交时间之后更新的记录。
支持的查询类型
Hudi 支持三种类型的查询:
-
对实时数据的快照查询,使用列式和基于行的存储的组合
-
增量查询,用于记录在特定时间之后插入或更新的更改流
-
读优化查询,使用列式存储提供改进的查询性能
表类型
针对工作负载的性能优化,Hudi 支持两种类型的表:写时复制(COW)和读时合并(MOR)。
COW 甚至对单个记录更改也会再次写入整个 Parquet 文件。每当用户执行任何事务时,Hudi 都会创建一个新的 Parquet 文件,其中包含先前版本的所有记录以及该事务的更改。这种方法使更新速度变慢,但查询性能更快。
MOR 不会创建现有文件的副本。它只在使用 Avro 格式创建的另一个日志文件中维护事务中执行的更改。当读取器执行查询以检索结果时,Hudi 合并更改日志以创建一个新的 Parquet 文件,读取器可以使用它来检索数据。MOR 最适合频繁更新表,但对于大量未压缩的小尺寸更改日志文件,可能会影响查询性能。
如果您计划使用 Hudi 作为实施基于湖仓的平台的表格式,您必须更详细地探索这些概念。要进一步了解这些概念,请参阅 Apache Hudi 常见问题解答。
Linux Foundation 的 Delta Lake
Delta Lake 是另一项在数据从业者中越来越受欢迎的技术。它是一种开放技术,最初由 Databricks 创建,后来作为 Linux Foundation 的一部分开源。它支持多个计算引擎,包括 Spark、PrestoDB 和 Trino。像 Iceberg 和 Hudi 一样,Delta Lake 也为数据湖提供事务能力,使其具有类似数据仓库的特性。
表格布局
图 3-12 展示了 Delta Lake 的底层数据管理目录结构。
像其他开放表格式一样,Delta Lake 由元数据层和数据层组成:
元数据层
元数据层包含一个 _delta_log 文件夹,该文件夹中包含 Delta Lake 为每笔交易创建的 JSON 文件。这些 JSON 文件包含元数据和交易细节。元数据包括与表模式相关的细节,包括属性名称、类型以及是否可为空。它还包含有关分区的信息。交易持有数据文件的详细信息,包括大小、修改时间以及每个属性中的最小/最大值。_delta_log 文件夹中的交易日志文件为每笔交易都有一个条目,指示作为交易的一部分是添加还是删除了数据文件。
数据层
Delta Lake 使用 Parquet 文件格式存储数据,并使用 Snappy 作为数据压缩的默认算法。
关键特性
Delta Lake 提供了多个特性,使数据湖能够像数据仓库一样运行:
ACID 支持
多个写入者可以同时修改一个表。即使另一个作业更改了表,读取者也可以继续查看一致的数据。
**更新、删除和合并支持 **
您可以快速删除或更新记录,以实现诸如慢变维度(SCD)或流式插入更新操作等用例。
时光旅行
您可以维护所有版本的记录,并根据时间戳或版本号获取任何先前版本。
模式强制和演变
模式强制功能确保在数据插入过程中拒绝任何具有模式变化的记录。Delta Lake 还支持模式演变,以适应具有元数据变化的源记录,以确保没有数据丢失。
批处理和流处理统一
任何 Delta 表都可以是批处理表、流处理源或接收器,从而使用户能够为批处理和流处理用例实施统一的代码。
清理
清理命令有助于删除旧版本的文件,只保留基于特定时间戳或版本号的所需版本。
优化和Z-顺序
优化功能通过将多个“小”文件压缩为较大的文件来减少文件数量。Z-顺序重新组织存储中的数据,使查询读取的数据更少,处理更快。这也帮助查询跳过大量不需要的数据文件。
注意
删除向量是 Delta Lake 等开放表格式采用的另一种存储优化技术。每当在 Delta Lake 中删除记录时,它会重写 Parquet 文件。某些 delta 操作可以使用这些向量来标记已删除的记录而不重写文件。后续的读操作可以基于这些删除向量跳过这些记录。在撰写本书时,删除向量功能在 Delta Lake 中处于实验支持模式。
克隆 Delta 表的“浅”克隆创建特定表版本的副本,而无需复制源文件。Databricks Delta Lake 还提供“深度”克隆,它会在克隆表目录中复制源文件。克隆可以帮助进行诸如定期备份和创建测试数据等活动,使用户能够使用特定表版本。
以上所有特性,以及与 Spark 的深度集成和微软与 Databricks 的支持,使 Delta Lake 成为实施湖仓平台的首选表格式之一。如果您想深入了解 Delta Lake,请参阅 Tomer Shiran、Jason Hughes 和 Alex Merced(O’Reilly)的《Delta Lake: The Definitive Guide》。
相似性、差异和使用场景
现在我们已经讨论了三种表格式的底层结构和特性,让我们基于关键设计参数来比较它们。我们将只关注那些在选择表格式时能帮助你做出设计决策的实际设计方面:
ACID 支持
Iceberg、Hudi 和 Delta Lake 都为事务提供了 ACID 保证。它们还使数据湖支持记录级别的更新和删除操作。这个特性使这些技术适合实施湖仓架构,并将它们与以前用于在数据湖中查询数据的 Hive 格式区分开来。
时光旅行
时光旅行是湖仓平台的关键特性之一,所有三种表格式都支持这一特性。这些表格式都可以保留旧版本的数据,并根据版本号或时间戳恢复数据。
模式演进
所有三种格式都支持模式演进特性。你可以轻松地添加、删除或重命名列,而无需重新写入数据。
增量数据处理支持
增量处理是构建 ETL 流水线的重要特性:
- Hudi 通过将追加、更新和删除作为变更流进行跟踪,支持高效的增量处理。它具有记录级索引,可以高效处理这些流。
- Delta Lake 有一个类似的特性,称为变更数据馈送,在本书撰写时处于实验支持模式。
- Iceberg 也有类似的特性,但仅支持追加。替换、覆盖和删除的支持尚未提供。
分区和集群
分区和集群是常用于性能优化的常见技术:
- Iceberg 有一个支持分区演进的独特特性。它可以帮助你在不重写数据的情况下更新分区。
- Delta Lake 有一个称为液态集群的特性(在本书撰写时处于实验支持模式),可以帮助更改集群列而不重写数据。
- 类似地,Hudi 使用集群来改进查询性能,并在数据演变时调整数据布局。
文件格式支持
所有三种表格式都支持 Parquet,这是现代数据平台最常采用的文件格式之一:
- Iceberg 支持 Parquet、ORC 和 Avro。
- Hudi 支持 Parquet 和 ORC。
- Delta Lake 仅支持 Parquet。
数据质量验证
数据质量验证有助于验证源数据并拒绝任何错误记录:
- Delta Lake 支持约束以确保数据质量和完整性。它提供了 NULL 约束来验证 NOT NULL 值,并提供 CHECK 约束来验证每个输入记录的指定布尔表达式(例如,product_id > 10)是否为真或假。
- Hudi 也有一个称为预提交验证器的特性,在写入数据时检查数据质量。
- Iceberg 尚未有类似的数据验证特性。
采用和使用场景
所有三种格式都最适合实施基于湖仓的平台。各种产品供应商已开始在其服务中支持这些格式:
- Delta-Parquet 是组织在 Azure 上实现用例的流行组合。Delta Lake 在与 Spark 配合使用时表现出色,是 Spark 密集型生态系统的首选之一。
- 使用 AWS 的组织已开始采用 Hudi,因为 AWS 深度集成了 Hudi。
- 许多组织正在考虑 Iceberg,因为它支持多种文件格式、分区演进特性,并得到了许多供应商产品(包括 Dremio、Tabular、Starburst 和 Snowflake)的支持。
互操作性
随着这些表格式的发展,你可能会看到不同平台为不同用例使用不同格式,以及这些开放格式之间的互操作性。Delta Universal Format (UniForm) 和 Apache XTable 可能只是此类倡议的开始。这将进一步促进湖仓平台的开放性,并使用户避免在为其平台选择单一表格式时做出艰难决策。我们将在第九章中更详细地讨论这些互操作性特性。
我们已经介绍了一些在设计湖仓平台时可以考虑的关键特性。根据你的用例,还有许多其他特性可以探索。然而,我建议不要仅根据最新和最先进版本中的可用特性做出最终设计决策。所有这些格式都在不断演进,可能会很快支持当前缺失的特性。在设计系统时,还应考虑其他关键因素。我们将在下一节中讨论这些设计考虑因素。
关键设计考虑因素
到目前为止,我们已经讨论了文件和表格式及其关键特性。现在是时候讨论选择开放表格式以实现平台时需要考虑的关键因素了。
做出设计决策并不容易。如果选择的是具有相似特征的新技术,这将变得更加具有挑战性。在本节中,我将讨论在决策时可以考虑的具体因素。根据你们组织的批准技术栈,在评估技术时可以将这些考虑因素作为指导。
生态系统支持
在决定表格式时,考虑你计划构建的完整生态系统是至关重要的。你是否在实施一个多云系统?你计划仅使用其中一个云系统来实现数据平台吗?你是否计划与其他供应商的产品进行互补?
例如,如果你的技术环境使用 Azure,并且已经在 Databricks 上进行了投资,那么使用 Delta-Parquet 组合是有意义的,因为它在微软生态系统中得到了深度支持。
如果你的实现基于 AWS,可以考虑 Hudi,因为多个 AWS 服务(如 Glue、EMR、Athena 和 Glue Catalog)与 Hudi 有深度集成。如果你需要在 Athena SQL 中写入支持,可以考虑 Iceberg。在撰写本文时,Iceberg 是唯一支持 Athena SQL 中写入操作的格式。
始终查看 CSP 文档以了解是否存在任何限制。一个很好的例子是 Azure Synapse Serverless SQL 的限制或 Amazon Athena 使用 Delta Lake 格式的限制。
社区支持
对于开源技术,社区贡献和支持对于解决问题、实施更改和持续创新至关重要。Iceberg、Hudi 和 Delta Lake 拥有活跃的社区、Slack 频道和其他定期讨论的社区活动。
图 3-13 显示了这些技术的 Git 仓库的简单比较。Git 仓库有三个关键参数:Stars、Forks 和 Watchers。这些参数可以让你比较和了解它们的流行度和采用情况。
如果只考虑仓库的 Stars,Delta Lake 是最受欢迎的,尽管 Databricks 开源 Delta Lake 的时间比 Hudi 和 Iceberg 晚得多。Hudi 的 Forks 和 Watchers 数量远超过其他两个。如图表所示,这一趋势在 2023 年中至 2024 年中这一年内保持不变。
这些图表是通过参考这三种表格式的各个仓库生成的:
- GitHub—apache/iceberg
- GitHub—apache/hudi: Upserts, Deletes And Incremental Processing on Big Data
- GitHub—delta-io/delta
支持的文件格式
这些开放表格式支持的文件格式可能会显著影响你的设计决策,特别是当你希望将现有的大数据工作负载迁移到湖仓平台时。
例如,考虑一个用例:你的现有本地环境使用 Hortonworks Data Platform (HDP),大多数数据存储文件为 ORC 格式。在这种情况下,你可以考虑 Iceberg 或 Hudi,因为它们支持 ORC 格式。但是,如果你使用 Azure 或 Databricks 平台并搭配 Delta Lake,它将不支持 ORC 文件格式。在这种情况下,你必须将所有现有的 ORC 文件转换为 Parquet,因为 Delta Lake 只支持 Parquet 文件格式。将大量历史数据从 ORC 转换为 Parquet 可能是一个重要的活动,并且是做出设计决策的关键因素。在设计新的湖仓平台时,考虑现有的数据存储格式。
支持的计算引擎
由于这些表格式仍在不断发展,它们尚未完全支持所有的计算引擎。Iceberg、Hudi 和 Delta Lake 支持广泛采用的开源计算引擎,如 Spark、Trino、Presto、Flink 和 Hive。然而,在大多数情况下,你可能会使用一些领先 CSP(云服务提供商)的本地服务,如 Amazon Athena、Google BigQuery 或 Azure Synapse Analytics。在使用这些商业计算引擎时,表格式可能会有一些限制。在做出设计决策之前,务必仔细评估这些限制。
例如,假设你使用 Azure 作为云平台,并希望使用 Iceberg,因为它支持各种文件格式和分区演进特性。然而,Synapse 仅对 Delta Lake 格式有本地支持。在这种情况下,你将不得不手动在 Synapse Spark 笔记本中安装和配置 Iceberg 库,或者使用 HDInsight 集群等替代方法来处理 ADLS 上的 Iceberg 文件。
计算引擎与表格式之间的兼容性是做出设计决策时的重要考虑因素。随着表格式和计算引擎的发展,它们将开始支持其他技术。我们将在第五章中更详细地讨论计算引擎。
支持的特性
每种开放表格式都提供标准特性,如 ACID 支持、模式演进和时光旅行。然而,一些格式提供独特的特性,如下:
- Iceberg 提供分区演进和隐藏分区。
- Hudi 提供批量加载优化、高效的增量处理以及 COW 和 MOR 表选项。
- Delta Lake 提供数据共享、将现有 Parquet 文件转换为 Delta 以及内置的数据质量验证。
如果这些特性在你的用例中起到重要作用,请考虑提供这些特定特性的表格式。随着这些技术的进一步发展,可能值得根据相关用例考虑混合使用表格式,而不是将平台用户限制在单一格式上。
商业产品支持
大多数开源技术都有 CSP 或其他产品供应商提供的等效托管产品。Databricks 创建了 Delta Lake,并将其作为湖仓平台的核心组件。Hudi 的创建者创立了 Onehouse,一个 Hudi 平台的商业产品。Dremio 和 Tabular 提供托管 Iceberg 来构建湖仓。这些商业产品通过添加贡献和新特性,往往有助于社区的成长。如果你想使用商业产品来实现湖仓架构,请评估这些产品。需要考虑的一些关键点是多云支持、易用性、实施特性、性能优化以及(商业产品最重要的考虑因素)总体拥有成本 (TCO)。
当前和未来版本
一种表格式可能没有其他表格式的所有特性。从其最新版本中缺失的特性不应成为拒绝特定格式的唯一理由。随着格式的发展,这些缺失的特性可能会在未来版本中提供。
例如,考虑最新的 Delta Lake 版本在 Azure Synapse Spark 池中不可用。如果你想使用最新版本的特性,必须等到 Azure 提供它,或者寻找替代实施方法。根据你的用例的时间敏感性和重要性来做出选择。
性能基准测试
性能基准测试是一个有争议的参数,可能不是决定特定技术的最佳方法。许多供应商和系统集成 (SI) 合作伙伴根据事务处理性能委员会 (TPC) 标准进行基准测试,并发布比较结果。
比较不同技术的基准测试需要对这些技术的所有配置和设置有深入了解。产品供应商对自己的产品有很好的了解,但可能不清楚竞争产品的关键设置,从而获得最佳性能,这可能导致执行过程中出现不一致的观察结果。TPC 为标准查询和数据集提供指导,但无法提供因工具而异的技术特定配置。
另一种选择是在受控环境中独立进行基准测试,仔细考虑所有配置和设置。在这种情况下,你必须投入大量时间和精力。在当今快节奏的世界中,你没有时间(和预算)来学习所有技术并进行基准测试!
第三方进行的基准测试可以被认为是更好、公正和可靠的。实际的方法是使用这些基准测试报告作为参考,以验证你首选表格式的性能,但不要仅根据基准测试结果做出最终决定。
TPC 是什么?
TPC 是由会员公司和协会组成的组织,为测试各种工具和技术的性能基准提供指导。
TPC 提供了几个决策支持系统的基准测试框架,称为 TPC-H 和 TPC-DS。许多产品供应商使用 TPC-DS 对现代数据平台进行性能基准测试。TPC-DS 提供了一组 99 个查询,复杂性和扫描的数据量各不相同,用户可以基于基准测试框架提供的标准数据模型在大数据集上执行这些查询。你会发现大多数供应商平台的 TPC-DS 基准测试结果,可以作为参考。
比较
在做出最终的表格式决策之前,请务必查看你计划用于实现数据平台的各个平台供应商的各种比较、博客和文章。
大多数时候,你在决定表格式之前已经决定了云平台。原生云服务可能与某种格式比其他格式更兼容,因此请务必参考其文档以了解表格式的限制(如果有),并做出决定。
例如,AWS 发布了一篇详细的博客,比较了三种格式及其与 AWS 的集成。查找专注于 AWS 与所选表格式集成的信息。
共享特性
实现湖仓架构的一个关键驱动力是其能够轻松与消费者共享数据。无需在湖仓中复制或复制数据。此外,消费者不需要与生产者在同一供应商平台上。湖仓有助于通过数据市场实现数据民主化和共享特性。在决定底层表格式时,考虑它们提供的共享特性。Delta Lake 通过其 Delta 分享特性以及细粒度访问控制支持数据共享。
在评估不同的表格式时,可以考虑这些要点。为了做出最终决策,最好的方法是综合考虑你的数据平台,考虑你们组织的整体技术栈和计划实施的用例。
关键要点
以下是我们在本章中讨论的文件格式和表格式的简要总结。表3-4和表3-5总结了文件格式和表格式之间的比较。
表3-4. 文件格式比较
| 文件格式 | 特性 |
|---|---|
| Parquet | |
| 存储类型: 列式存储 | |
| 最适合: 分析查询,Spark 工作负载 | |
| 压缩: 比 Avro、CSV 文件更好的压缩 | |
| 扫描数据: 少得多,仅与所选列相关 | |
| 采用情况: 广泛采用,作为 Spark 的默认文件格式 | |
| ORC | |
| 存储类型: 列式存储 | |
| 最适合: 分析查询,在 Hive 中启用 ACID 特性 | |
| 压缩: 比 Avro、CSV 文件更好的压缩 | |
| 扫描数据: 少得多,仅与所选列相关 | |
| 采用情况: 在 HDP 用户中流行 | |
| Avro | |
| 存储类型: 行存储 | |
| 最适合: 行级事务,频繁插入/更新,写密集型工作负载 | |
| 压缩: 比 CSV 文件更好的压缩,不如 Parquet 和 ORC | |
| 扫描数据: 比 Parquet 和 ORC 多得多 | |
| 采用情况: 由于其紧凑格式和模式演进特性,广泛用于 Kafka 消息 |
表3-5. 开放表格式比较
| 表格式 | 特性 |
|---|---|
| Iceberg | |
| 文件格式支持: Parquet, ORC, Avro | |
| 适用用例: 需要更改分区的工作负载,支持多种文件格式,非 Spark 计算引擎 | |
| 关键特性: ACID 兼容,时光旅行,分区演进 | |
| 限制: 无数据质量约束 | |
| 深度集成: AWS, GCP, Dremio, Tabular, Snowflake | |
| Hudi | |
| 文件格式支持: Parquet, ORC | |
| 适用用例: 增量处理,AWS 实现,多种文件格式 | |
| 关键特性: ACID 兼容,时光旅行,增量处理,索引 | |
| 限制: 无分区演进,不支持 Avro | |
| 深度集成: AWS, Onehouse | |
| Delta Lake | |
| 文件格式支持: Parquet | |
| 适用用例: 使用 Spark 引擎的工作负载,Azure 实现 | |
| 关键特性: ACID 兼容,时光旅行,克隆,Z-ordering,共享 | |
| 限制: 仅适用于 Parquet | |
| 深度集成: Azure, Databricks, Microsoft Fabric |
请记住这些要点:
- 任何单一的文件或表格式都不能提供所有你可能需要的最佳特性或易于集成的特性。你要么需要在某些特性上妥协,要么计划在你的数据平台中使用多种格式。
- 你应该进行概念验证或实施试点阶段,以了解哪种格式最适合你的用例,并能很好地与云平台集成。
- 所有这些格式都在不断发展。任何缺失的特性可能很快就会提供。不要仅仅因为缺失某个特性而拒绝一种表格式。
希望本章能让你更好地理解存储层及其组件。在下一章中,我们将讨论元存储和数据目录及其在湖仓架构中的重要性。