文章目录
- 前言
- Lakehouse 存储关键概念
- 行存储与列存储
- 基于存储的查询性能优化
- Lakehouse 存储组件
- 云储存
- 文件格式
- Apache Parquet
- Apache ORC
- Apache Avro
- 相似点和差异点
- 表格格式
- Apache Hive
- Iceberg
- 特性和优点
- Apache Hudi
- 特性和优点
- Delta Lake
- 特性和优点
- 相似点和差异点
- 总结
前言
存储层是任何数据平台的核心,在基于lakehouse架构的平台中,它对于高效持久化各类数据、提高查询引擎的性能发挥着重要作用。
Lakehouse存储层由云存储、文件格式和表格式组成。
本文将说明与 Lakehouse 存储相关的基本概念、行式存储和列式存储之间的区别,以及存储格式是如何与性能密切相关的。
然后,将深入探讨用于数据分析场景的存储格式、使用每种格式的好处以及构建数据平台时应考虑的关键功能。
了解了上边的概念后将讨论湖仓一体中的开放表格式,包括其功能和优点,以及在使用的时候需要注意的地方。
Lakehouse 存储关键概念
存储层是数据生态系统的支柱,当实施数据平台时,将需要一个持久、可靠且高度可用的存储层,可以保存大量所有类型的历史数据。除了上述功能之外,lakehouse 平台还需要一个存储层,该存储层还可以实现快速检索、支持 ACID 功能并保留旧版本的数据。
行存储与列存储
所有创建表或在表中插入数据的操作,都会以文件形式存储在物理磁盘上。在现代数据平台中,一般使用云存储来保存数据,有两种存储数据的方法:行式存储和列式存储。
下边对行存储和列存储进行简单的介绍说明,如下图所示,有一个产品表:
product ID | name | type |
---|---|---|
1 | 键盘 | 电脑配件 |
2 | 耳机 | 电脑配件 |
3 | 手机壳 | 手机配件 |
行式存储将在物理磁盘上存储整行数据:
1 | 键盘 | 电脑配件 | 2 | 耳机 | 电脑配件 | 3 | 手机壳 | 手机配件 |
---|
当查询数据时,它会从磁盘读取完整的行。当查询想要读取数据中的所有列时,这非常有用。然而,数据分析工作一般只会查询指定的列,由于基于行的存储的性质,查询必须读取许多记录中的所有列,而不管查询所需的列数是多少,导致消耗资源大,查询效率低。
列式存储会对相同类型的数据进行压缩,只会扫描查询指定的列,而不会扫描整行数据,查询效率高。
基于存储的查询性能优化
存储不仅仅是保存数据,它还使计算引擎能够通过减少要扫描的数据来更快地检索所需的结果。决定性能的不仅是计算引擎,还有底层存储。
任何分析查询的数据检索时间都会受到扫描数据量的严重影响。扫描的数据越少,获取结果所需的时间就越短。现代文件和表格式有助于最大限度地减少查询检索结果所需扫描的数据,该过程被称为数据跳跃或行跳跃。
有多种方法可以跳过不需要的数据,包括:
- 仅选择需要查询的字段
- 使用分区表
- 维护列统计信息
- 创建索引
Lakehouse 存储组件
Lakehouse存储层由三个主要部分组成,
- 用于物理存储数据的云存储。
- 用于压缩数据并支持分布式处理的开放文件格式。
- 开放的表格式提供事务处理能力和高效的数据检索。
云储存
存储层负责持久化保存 Lakehouse 架构中的所有数据,云存储最适合存储大量此类数据,这些数据的性质、类型、大小和接收速度各不相同。
下图显示了 Lakehouse 存储层以及可用于实现它的不同云对象存储技术:
存储特性
用于实现物理存储的技术应表现出以下基本特征:
- 持久性:底层存储硬件要确保不会损坏,可以根据数据所需保留时间长期保存数据,并且需要有损坏后的数据恢复措施。
- 可用性:存储服务应该不间断的为数据消费者提供可用服务,查询数据,即使存储服务宕机,也要有相应的备份措施,提供数据。
- 可扩展性:存储服务应该易于扩展,并且能够根据数据增长需求进行扩展,而无需任何手动干预。
- 成本优化:应该提供高性能和相对低性能的不同价格的存储层,冷热数据按需存储在不同的存储层中,以达到成本与性能之间的平衡。
- 安全:存储层最重要的特征之一是提供内置安全性,它应该提供保护存储层内静态数据的功能。
大多数云厂商的云存储(S3, OSS等)都提供上边的特性,所以在实践 Lakehouse 架构时首选云对象存储,而不是 HDFS。
文件格式
存储层中的下一个组件是文件格式,定义了在云存储上存储数据的方式:行存储或列存储。现代文件格式为了支持分布式处理的能力,会对文件数据进行压缩和分割成多个小文件。
一些流行的文件格式,包括 CSV、JSON 和 XML,在处理大数据时存在一些关键限制:
- 压缩能力有限,占用存储空间大。
- 数据检索时间长,分析查询通常需要很长时间才能获取所需的结果。
- 扫描的数据不仅限于所需的列,查询通常会扫描整个数据集来处理结果。
- 没有内置 schema,在读取这些文件时必须显式定义 schema。
- 需要处于未压缩的原始形式,才能支持分布式处理。
什么是可分割文件格式?
在分布式处理中,数据分布在各个集群上以支持并行处理。当文件存储在这些分布式存储上时,需要将其存储到各种数据块或块中,以便多个处理引擎可以读取这些块。用于存储数据的文件格式应该支持这种将文件分割成多个块的方式。大数据系统中的文件通常容量很大并经过压缩以节省存储空间并提高性能。它们的压缩形式应该是可拆分的,以执行分布式处理。大数据文件格式在使用支持的压缩算法(如 Snappy、LZO、BZIP2 等)进行压缩时支持此类拆分。但是,传统格式(如 CSV)在使用 GZIP 压缩进行压缩时无法进行拆分。
目前社区比较流行的三种压缩文件格式包括:
- Apache Parquet
- Apache ORC
- Apache Avro
Apache Parquet
Parquet 提供比 CSV 和 JSON 文件格式更好的压缩比,并提供强大的处理复杂数据的性能。
文件结构
下图简单展示了 parquet 文件格式布局:
- 每个 parquet 文件都由页眉、页脚和数据块组成。
- header 包含指示文件采用 parquet 格式的详细信息。
- 数据块由多个行组组成,这些行组逻辑上组合了文件中的各个行。
- 行组由文件中存在的列组成。
- Parquet 将每列中的值存储为页, 页是 Parquet 中最小存储单位。
- 文件页脚由行组和列的元数据组成,元数据包括有助于数据跳过的最小/最大值等统计信息。
优点
- 使用列式存储压缩,显著减小文件大小
- 可以仅扫描查询的列,不需要扫描所有列,提升查询效率
- Parquet 文件还记录了文件的 schema 信息,这有助于轻松地将数据加载到表中,并使用 Apache Spark 等框架拆分文件以进行分布式处理。
Apache ORC
与 parquet 一样,也是一种列式文件格式,是 Hive 标准 RC 格式的继承者。 Apache ORC 提供 ACID 支持,具有内置索引以加快数据检索速度,并支持结struct 、list 和map 等复杂数据类型。
文件结构
- 每个 ORC 文件包含页眉、页脚和多个称为 条(stripe)的数据块。
- HEADER 包含指示该文件为 ORC 格式的详细信息。
- 每条 stripe 由索引数据、行数据和条带页脚组成。
- 索引数据保存所存储数据的索引, 它还具有每列的最小值和最大值。
- 行数据保存扫描中使用的实际数据。
- Stripe 页脚包含与每列相关的详细信息,包括编码、位置、最小值和最大值。
- 文件页脚包含与文件中的stripe 相关的统计信息:行数以及可帮助数据跳跃的信息。
优点
- ORC 与 Hive 进行了深度集成,主要是作为在 Hadoop 中存储数据的文件格式而创建的,这些数据将使用 Hive 进行处理。
- ORC 是一种列式存储,数据压缩率更高。
- ORC 是唯一支持 Hive 事务处理的文件格式。
Apache Avro
文件结构
- HEADER 由文件元数据组成,包括 schema、压缩代码的信息和随机生成的文件同步标记。
- Block 组成:该块中的对象数量,该块的大小(压缩后),以压缩形式存储为序列化对象的数据,文件的 16 位同步标记
优点
除了和Apache Parquet 和 Apache ORC 一样的列式存储优点,Apache Avro 还提供了一些独特的功能,有助于存储和处理大量数据:
- 其自描述性意味着它将schema 与数据一起存储,任何消费者都可以在读取数据时获取 schema。
- schema 以 JSON 或 Avro iDL (AVDL) 格式存储,易于人类阅读,而实际数据以二进制存储以获得更好的压缩比。
- Avro 支持 schema 推演,使其成为 ETL 中可用的 schema 选择。
- Avro 文件是可分割的,这意味着它即使以压缩形式也可以用于分布式处理,从而有助于更快的数据处理。
- 它支持多种语言,包括java js、c、c++、C#、python、ruby
相似点和差异点
所有这些文件格式的目的都是为了有效地存储数据并提高读取数据时的查询性能。这三者都具有类似的功能,有助于实现这些目标;然而,它们根据存储和压缩数据的方法存在关键差异,下边是其中的相似点和差异点说明。
支持的数据格式
- 所有三种格式都支持存储大量结构化和非结构化数据。
压缩
- 所有三种文件格式都提供比 CSV、TXT 和 JSON 文件更高的压缩率。这有助于减少存储容量,也有助于提高查询性能。与 AVRO 文件格式相比,Parquet 和 ORC 提供更好的压缩。
下图是使用它们进行压缩 2G CSV 数据,三种压缩率对比:
可拆分
- Parquet、ORC 和 Avro 是可拆分的,可以支持分布式处理而无需解压缩数据,从而减少数据扫描量并加快数据检索速度。
使用场景
- Parquet 在社区中广泛使用,可以说是这三种格式中最受欢迎的格式,被许多计算框架集成,包括 Spark 等。
- ORC与Hive深度集成,是唯一支持具有ACID特性的Hive的格式。
- 由于 schema 使用简单,Avro 非常适合 ETL 工作方式。
文件存储格式
- Parquet 和 ORC 遵循列式存储数据的格式,但具有不同的实现方法。 Parquet 将数据存储为页,而 ORC 将数据存储为条。 Avro 遵循基于行的方法并将数据存储在块中。这些不同的方法会影响其压缩率和数据跳过能力。
扫描数据
- 与 Parquet 和 ORC 相比,Avro 为写入操作提供了更好的性能。 Parquet 和 ORC 在出于分析目的读取列子集时表现更好,因为它们可以根据列值跳过数据。
- 下图展示了从不同格式的文件中查询单列所扫描的数据量:
CSV 和 Avro 格式创建的表上运行的查询扫描了完整的数据,而 ORC 和 Parquet 表扫描的数据非常少,只扫描了所需的列
schema 推演
- Avro 支持schema 推演 - 可以添加或修改列。 Parquet 和 ORC 仅支持在末尾添加列。
说明
对于查询分析工作方式,列式存储最适合数据检索。 ORC 和 Parquet 都提供良好的压缩级别并支持更快的数据检索。然而,ORC 最适合 Hive,而 Parquet 与 Apache Spark 适配很好。考虑到大多数现代供应商数据平台都采用了 Parquet,我们可以将其视为存储分析数据的首选。可以使用 Avro 对其进行补充,以存储 ETL 过程中使用的原始数据。在选择存储文件格式之前,我们应该仔细考虑使用场景。
表格格式
表格格式有助于组织每个表格的数据文件,它由与数据文件相关的信息组成,如schema 详细信息、文件创建/更新时间、每个文件中的记录数、记录级别操作类型(添加/删除)等。表格式使数据湖具有 ACID 功能,支持更新/删除和数据跳过功能,从而提高查询的性能。
Apache Hive
Hive 拥有 Hive-Server 2 (HS2)、Hive Metastore (HMS) 和 Beeline(Hive 命令行界面)等关键组件作为其服务的一部分。它使用 HDFS 存储数据并使用 MapReduce 处理数据。
说明
Hive 有一个称为 Hive Metastore (HMS) 的中央元数据存储库,用于存储 Hive 表的schema 详细信息。它还存储与每个表的分区相关的信息。 许多数据平台都使用 HMS 作为存储元数据的元存储。
hive 表目录结构如下:
当在 Hive 中创建表时,它会将数据存储在 HDFS 中,将 schema 存储在 HMS 中。 Hive 表目录包含其根表文件夹下的所有文件。如果对该表进行分区,它将创建额外的分区级目录并将相关数据文件放置在这些目录下。
数据始终驻留在数据湖(在本例中为 HDFS,也可以在 OSS 对象存储)上,不会加载到任何其他专用仓库存储中,从而使用户能够构建像 Lakehouse 这样仅具有单个存储层的系统。
优点
- 支持分区
- 多种存储格式,包括列式存储和 CSV, JSON 等
- 支持多种查询计算引擎,包括 Spark, Presto 等
缺点
- 不支持事物机制
- 查询计划时间长,性能有限
- 不支持更新、删除操作
无法通过执行 SQL 命令直接更新或删除 Hive 表中存在的任何记录。由于数据驻留在不可变的 HDFS 上,因此没有直接的方法来更新或删除记录。如果要修改一些记录,则必须首先识别它们所在的分区,删除所有这些分区,然后使用修改的记录重新创建整个分区。这会导致更长的处理时间以及不必要的大量数据删除/重新创建。
所有这些限制导致了Hive 成为现代表格格式的演变,社区后边推出了Apache Iceberg、Apache Hudi 和 Delta Lake 三种现代表格格式,数据存储在云对象存储中,它们只提供事物机制:
Iceberg
Apache Iceberg由两大部分组成——元数据层和数据层:
Catalog
catalog 列出了表位置并指向最新的元数据文件
元数据层
元数据层由多个元素组成:
- 与 Hive 元存储一样,Apache Iceberg 将schema 详细信息分区信息存储在元数据文件中。
- 元数据文件中有一个称为快照的部分。每个快照都指向一个称为“清单列表”的文件。对于每个新事务,都会将新快照添加到元数据文件中。
- 清单列表指向属于特定快照的所有清单文件。
- 这些清单文件存储数据文件列表和列统计详细信息。
数据层
Apache Iceberg 支持 Apache Parquet、Apache ORC 和 Apache Avro 文件存储格式。
特性和优点
ACID 支持
- ACID 支持是 Lakehouse 平台最重要的功能之一。 Apache Iceberg 支持 ACID 属性,并为并发读/写提供一致性和隔离性。
schema 推演
- Apache Iceberg 支持schema 推演,有助于适应源系统上的任何 schema 更改,以确保存储数据时不会丢失数据。
隐藏分区
- 在 Hive 等早期表格式中,为了有效利用分区,必须始终在过滤条件中使用分区列。无法对这些分区列使用任何转换。例如,当在过滤条件中使用月份时,按日期 (YYYYMMDD) 分区的表无法将数据扫描限制为特定月份。
- 使用 Apache Iceberg,可以获得一个称为“隐藏分区”的功能,帮助对分区列执行转换并根据分区转换限制扫描。
分区演变
- 随着数据随着时间的推移而增加,可能需要更改现有分区以获得更好的查询性能。在这种情况下,唯一的选择是根据新分区重写表。 Apache Iceberg 提供了一项功能来演变这些分区,而无需重写数据。
时间回溯(重点)
- 时间回溯有助于查询历史数据并查看已更新或删除的记录的先前版本。
支持的文件格式
- 支持Apache Parquet、Apache ORC 和 Apache Avro 三种存储格式。
Apache Hudi
Hudi(Hadoop Upserts Deletes and Incrementals)代表其执行记录级更新插入和删除以及支持增量数据处理的能力。
文件结构如下:
元数据层
Apache Hudi 将事务日志存储在 .hoodie 目录中。表元数据存储在 .hoodie 目录下的元数据目录中。 Apache Hudi 还创建一个“hoodie.properties”文件来保存表级配置,适用于写入和读取数据。
数据层
根据用于表分区的列,在基本路径下为不同的列值创建子目录来存储数据文件。 Apache Hudi 将这些数据文件存储为基本文件或日志文件。
特性和优点
Apache Hudi 提供了多种可以帮助实现 Lakehouse 平台的功能:
支持 ACID、更新和删除
- Apache Hudi 支持具有 ACID 事务保证的数据湖,并提供写入器和读取器查询之间的隔离。它还使用户能够执行事物级别的更新插入和删除。
时间回溯
- 查询历史版本数据
优化过的查询性能
- 基于集群化、数据压缩、索引创建等功能提供各种性能优化手段。
提交时间线
- 维护在表上执行的所有提交的时间线,以及与作为每个事务的一部分创建的文件相关的信息。增量查询使用这些提交来获取在特定提交时间后插入/更新的记录。
支持的查询类型
Apache Hudi 支持三种类型的查询
- 使用列式和行式存储的组合对实时数据进行快照查询。
- 对特定时间后插入/更新的记录的更改流进行增量查询。
- 使用列式存储优化读取查询性能。
表格类型
Apache Hudi 支持两种类型的表格式:写入时复制 (COW) 和读取时合并 (MOR),对查询性能进行优化。
- 即使对于单个记录更改,COW 也会再次写入整个 parquet 文件。每当用户执行任何事务时,Hudi 都会创建一个新的 parquet 文件,其中包含先前版本的所有记录以及该事务的更改。使用这种表格式时,更新速度较慢,但有助于提高查询性能。
- MOR 不会创建现有文件的副本。它仅在使用 Avro 格式创建的另一个日志文件中维护事务中执行的更改。当用户执行查询来检索数据时,Hudi 会合并更改日志以创建一个新的 parquet 文件,可以使用该文件来检索数据。 MOR 最适合频繁的表更新,但如果不进行压缩,可能会生成大量小文件,影响查询性能。
Delta Lake
它支持多种计算引擎,包括 Apache Spark、PrestoDB 和 Trino。与 Iceberg 和 Hudi 一样,Delta Lake 也为数据湖提供事务功能,使其具有类似数据仓库的功能。
文件目录结构
元数据层
元数据层由一个“_delta_log”文件夹组成,其中保存 Delta Lake 为每个事务创建的 JSON 文件。这些 JSON 文件包含元数据和事物信息。元数据包含与表schema 相关的详细信息,包括属性名称、类型以及是否可为空。它还保存有关分区的信息。该事务保存数据文件、大小、修改时间以及每个属性中的值的详细信息。
数据层
Delta Lake 使用 Apache Parquet 文件格式存储数据,并使用 Snappy 作为默认的数据压缩算法。
特性和优点
ADID 支持
- 多个写入者可以同时修改一个表。即使另一个作业更改了表,读者也可以继续查看一致的数据。
更新/删除/合并支持
- 可以快速删除或更新记录以实施缓慢更改维度 (SCD) 或流式更新插入操作等场景。
时间回溯
- 可以维护修改记录的所有版本,并根据时间戳或版本号获取任何以前的版本。
schema 使用和推演
- 使用 schema 可确保在数据插入过程中过滤掉不合法的数据,Delta Lake 还支持schema 推演,以适应具有元数据变化的源记录,以确保不会丢失数据。
批处理和流处理统一
- 所有表都可以作为批处理表,流处理的目标表或源表
数据回收
- 可以删除旧版本文件,并根据特定时间戳或版本仅保留所需的版本。
压缩合并小文件
- 对小文件进行压缩合并成大文件,减少查询的文件数量,加速查询速度。
克隆
- “浅”克隆有助于创建特定表版本的克隆,而无需复制源文件。 “深度”克隆,可以在克隆表目录中创建源文件的副本,在 session 中使用户能够使用特定的表版本。
相似点和差异点
ACID 支持
Iceberg、Hudi 和 Delta Lake 都为事物性提供 ACID 保证,它们还使数据湖能够以高性能的水平支持更新/删除操作。这一特性使得这些技术适合实现 Lakehouse 架构,并将它们与之前数据湖广泛采用的Hive 表格式区分开来。
时间回溯
时间回溯是 Lakehouse 平台的关键功能之一,所有三种表格格式都支持它。这些表格式中的每一种都可以保留旧版本的数据,并根据时间戳的版本号来恢复它。
schema 推演
所有三种格式都支持schema 推演功能,可以轻松添加、删除或重命名列,而无需再次重写数据。
支持增量数据处理
Apache Hudi 通过跟踪变更流的追加、更新和删除来支持高效的增量处理。它具有索引级记录来有效地处理这些流。
Delta Lake 也有一个类似的功能,叫做更改数据源。
Apache Iceberg 有类似的功能,但仅支持追加。缺少对替换、覆盖和删除的支持。
分区和集群
Apache Iceberg 有一个独特的功能来支持分区演化,它可以帮助我们更新分区而无需重写数据。Apache Hudi 使用集群来提高查询性能并随着数据的演变调整数据分区。
支持的文件格式
Apache Iceberg 支持 Parquet、ORC 和 Avro 文件格式。 Apache Hudi 支持 Parquet 和 ORC,而 Delta Lake 仅支持 Parquet。
所有三种表格式都支持 Parquet,这是现代数据平台最常用的文件格式。
数据质量验证
Delta Lake 支持约束以确保数据质量和完整性。它提供“NULL”约束来验证 NULL 值,并提供“CHECK”约束来验证每个输入记录的指定布尔表达式(示例,product_id > 10)是 true 还是 false。
Apache Hudi 还有一个称为“预提交验证器”的功能,用于在写入数据时检查数据质量。 Apache Iceberg 尚不具备此类验证功能。
选型和使用场景
所有三种格式都最适合实施基于 Lakehouse 的数据平台。各种产品供应商已开始支持这些格式作为其服务的一部分。 Delta-Parquet 是公司用来在 Azure 上实施用例的流行组合。 Delta Lake 在 Spark 中表现出出色的性能,是 Spark 密集型生态系统的首选之一。使用 AWS 的公司已开始采用 Hudi,因为 AWS 具有深度 Hudi 集成。许多公司正在考虑 Iceberg,因为它支持多种文件格式、分区演变功能以及许多供应商产品的支持,包括 Dremio、Tabular、Starburst 和 Snowflake。
注意:
这些是我们在设计 Lakehouse 平台时可以考虑的一些关键功能,我们可以根据我们的使用场景考虑多种其他功能。但是,我们应该避免根据最新版本中的可用功能做出设计决策。所有这些格式都在不断发展,迟早会开始支持缺失的功能。在设计系统时还应该考虑其他关键因素。
总结
- 任何单一文件或表格格式都无法满足我们想要的所有功能,我们要么必须在某些功能上做出妥协,要么计划在数据平台中采用多种格式。
- 我们应该执行 PoC 或实施试点阶段,以了解哪种格式最适合我们的使用场景并与我们的云平台集成良好。
- 所有这些格式都在不断发展,任何缺失的功能都可能迟早出现,不要仅仅因为缺少功能而拒绝使用其中的某种表格格式。