用于多云数据湖的 Delta Lake 和 MinIO

用于多云数据湖的 Delta Lake 和 MinIO

Delta Lake 是一个开源存储框架,用于在 Lakehouse 架构中的对象存储之上构建数据湖。Delta Lake支持 ACID 事务、可扩展的元数据处理以及统一的流式和批量数据处理。Delta Lake 通常用于为 Apache Spark 应用程序提供可靠性、一致性和可扩展性。Delta Lake 运行在现有数据湖存储之上,例如 MinIO,并与 Apache Spark API 兼容。

原始的 Delta Lake 论文(Delta Lake:基于云对象存储的高性能 ACID 表存储)描述了它是如何为云对象存储构建的。Vertica 测试将 Delta Lake 用于外部表时,他们依赖于 MinIO。HPE Ezmeral Runtime Enterprise 客户在 MinIO 上运行 Delta LakeMinIO 支持 Delta Lake 的持久性要求,因为 MinIO 在分布式和独立模式下对所有 i/o 操作都遵循严格的写后读和写后列表一致性模型,并且被广泛认可可以运行 Delta Lake 工作负载。

许多组织依靠 MinIO 和 AWS S3 等云原生对象存储来存储大型结构化、半结构化和非结构化数据集。每个表都存储为一组 Parquet 或 ORC 对象,并排列成分区。对大文件的查询基本上是快速执行的扫描。

如果没有 Delta Lake,更复杂的 Spark 工作负载,尤其是那些修改、添加或删除数据的工作负载,将在繁重的多用户/多应用程序负载下面临性能和正确性方面的挑战。多对象更新不是原子的,查询也不是孤立的,这意味着如果在一个查询中执行删除,那么其他并发查询将在原始查询更新每个对象时获得部分结果。回滚写入很棘手,更新过程中的崩溃可能会导致表损坏。真正的性能杀手是元数据——对于包含数百万个对象的大型表,这些对象是包含数十亿或数万亿条记录的 Parquet 文件,元数据操作可能会使构建在数据湖上的应用程序陷入僵局。


pasted image 0 (49).png


Delta Lake 旨在将数据库的事务可靠性与数据湖的水平可扩展性结合起来。Delta Lake 旨在通过云原生对象存储(如 MinIO)上的 ACID 表存储层支持 OLAP 风格的工作负载。如论文Delta lake 中所述:云对象存储上的高性能 ACID 表存储,“Delta Lake 的核心思想很简单:我们使用本身存储在云对象存储中的预写日志,以 ACID 方式维护有关哪些对象是 Delta 表的一部分的信息。” 对象以 Parquet 编码,可以由理解 Parquet 的引擎读取。多个对象可以“以序列化的方式同时更新,同时仍然实现高并行读写性能”。日志包含元数据,例如每个文件的最小/最大统计信息,比直接在对象存储中搜索文件“实现更快的元数据搜索数量级”。

Delta Lake 提供以下内容:

  • ACID 保证: Delta Lake 确保对数据的所有更改都写入存储并承诺持久性,同时以原子方式提供给用户和应用程序。您的数据湖中不再有部分或损坏的文件。

  • 可扩展的数据和元数据处理:所有使用 Spark(或其他分布式处理引擎)的读写操作都可以扩展到 PB 级。与大多数其他存储格式和查询引擎不同,Delta Lake 利用 Spark 扩展所有元数据处理,可以高效地处理 PB 级表的数十亿文件的元数据。

  • 审计历史和时间旅行: Delta Lake 事务日志记录了对数据所做的每一次修改的详细信息,包括对更改的完整审计跟踪。数据快照使开发人员能够出于审计、回滚或任何其他原因访问和恢复到早期版本的数据。

  • 架构实施和架构演变: Delta Lake 自动阻止插入与现有表架构不匹配的数据。然而,表模式可以显式和安全地发展以适应数据结构和格式的变化。

  • 支持删除、更新和合并:大多数分布式处理框架不支持数据湖上的原子数据修改操作。相比之下,Delta Lake 支持复杂用例的合并、更新和删除操作,例如变更数据捕获、缓慢变化的维度操作和流式更新插入。

  • 流和批统一: Delta Lake 表能够在批模式下工作,并作为流源和接收器。Delta Lake 可处理各种延迟,包括流式数据摄取和批量历史回填,以提供实时交互式查询。流作业以低延迟将小对象写入表中,然后通过事务将它们组合成更大的对象以获得更好的性能。

  • 缓存:依赖于对象存储意味着 Delta 表及其日志中的对象是不可变的,并且可以安全地缓存在本地——本地多云中的任何地方。

Lakehouse 架构,尤其是 Delta Lake,为基于对象存储的数据湖带来了关键的新功能。Delta Lake 可与大量且不断增加的应用程序和计算引擎一起使用,例如 Spark、Starburst、Trino、Flink 和 Hive,还包括用于 Scala、Java、Rust、Ruby 和 Python 的 API。Kubernetes 原生 MinIO 专为云而构建,可在任何地方(边缘、数据中心和公共/私有云)启用高性能、弹性和安全的数据湖应用程序。


pasted image 0 (50).png


三角洲湖档案

增量表是一起存储在目录(对于文件系统)或存储桶(对于 MinIO 和其他对象存储)中的文件集合。对对象存储的读写,Delta Lake使用路径方案动态识别存储系统,并使用相应的LogStore实现提供ACID保证。对于 MinIO,您将使用 S3A,请参阅存储配置 — Delta Lake 文档与 MinIO 一样,用于 Delta Lake 的底层存储系统能够进行并发原子读/写是至关重要的。  

创建增量表实际上是将文件写入目录或存储桶。通过写入(读取)Spark DataFrame 并指定格式和路径来创建(打开)增量表delta例如,在 Scala 中:

// Create a Delta table on MinIO:
spark.range(5).write.format("delta").save("s3a://<your-minio-bucket>/<path-to-delta-table>")

// Read a Delta table on S3:
spark.read.format("delta").load("s3a://<your-mnio-bucket>/<path-to-delta-table>").show()

Delta Lake 依赖于每个表一个桶,桶通常根据文件系统路径建模。Delta Lake 表是一个包含数据、元数据和事务日志的存储桶。该表以 Parquet 格式存储。表可以划分为多个文件。MinIO 支持 S3 LIST 以使用文件系统样式路径有效地列出对象。MinIO 还支持字节范围请求,以便更有效地读取大型 Parquet 文件的子集。  


pasted image 0 (51).png


由于行业领先的性能,MinIO 成为 Delta Lake 表的绝佳家园。MinIO 的可扩展性和高性能的结合使每一个工作负载,无论多么苛刻,都触手可及。MinIO 具有惊人的性能——最近的基准测试在 GET 上达到了 325 GiB/s (349 GB/s),在 PUT 上达到了 165 GiB/s (177 GB/s),只有 32 个现成的 NVMe SSD 节点。MinIO 不仅提供了为 Delta Lake 上最苛刻的工作负载提供动力所需的性能。

Delta Lake 存储桶很可能会包含许多 Parquet 和 JSON 文件,这与我们内置到 MinIO 中用作数据湖的所有小文件优化非常吻合。小对象与元数据一起保存,减少了读取和写入小文件(如 Delta Lake 事务)所需的 IOPS。

大多数企业都需要 Delta Lake 的多云功能。MinIO 包括主动-主动复制以在位置之间同步数据 - 本地、公共/私有云和边缘。主动-主动复制使企业能够构建多地域弹性和快速热-热故障转移。可以为每个存储桶或 Delta Lake 表单独配置复制,以实现最大的安全性和可用性。

与 Delta Lake 的 ACID 交易

ACID(原子性、一致性、隔离性和持久性)事务添加到数据湖是一件非常重要的事情,因为现在组织可以更好地控制数据湖中存储的大量数据,从而获得更大的信任。以前,依赖 Spark 处理数据湖的企业缺乏原子 API 和 ACID 事务,但现在 Delta Lake 使之成为可能。数据抓取写入后可以更新,并且支持ACID,即使应用在运行过程中失败,数据也不会丢失。Delta Lake 通过充当 Spark 和 MinIO 之间读写数据的中介来实现这一点。

Delta Lake 的核心是 DeltaLog ,它是用户和应用程序进行的交易的有序记录。用户对 Delta Lake 表执行的每个操作(如 UPDATE 或 INSERT)都是由多个操作或作业组成的原子提交。当每个操作成功完成时,提交记录为 DeltaLog 中的条目。如果任何作业失败,则提交不会记录在 DeltaLog 中。如果没有原子性,数据可能会在硬件或软件故障导致数据仅被部分写入的情况下损坏。

Delta Lake 将操作分解为以下一项或多项操作:

  • 添加文件——添加一个文件

  • 删除文件 - 删除文件

  • 更新元数据 - 记录对表名、架构或分区的更改

  • 设置事务 - 记录流式作业已提交数据

  • Commit info - 有关提交的信息,包括操作、用户和时间

  • 更改协议 - 将 DeltaLog 更新为最新的软件协议

它并不像看起来那么复杂。例如,如果用户向表中添加新列并向其添加数据,则 Delta Lake 会将其分解为组件操作——更新元数据以添加列并为添加的每个新文件添加文件——并将它们添加到完成时的 DeltaLog。

Delta Lake 依靠乐观的并发控制来允许给定表的多个读取器和写入器同时在该表上工作。乐观并发控制假定不同用户对表所做的更改可以在不发生冲突的情况下完成。随着数据量的增长,用户处理不同表的可能性也会增加。如果两个或多个提交同时发生,Delta Lake 会序列化提交并遵循互斥规则。通过这样做,Delta Lake 实现了 ACID 所需的隔离,并且在多个并发写入之后表看起来与这些写入连续且彼此分开发生时的表看起来相同。

当用户对自上次读取以来已修改的打开表运行新查询时,Spark 查询 DeltaLog 以确定是否有新事务已发布到表并使用这些新更改更新用户的表。这确保了用户的表版本与 Delta Lake 中的主表同步到最近的操作,并且用户不会对表进行冲突更新。

DeltaLog、乐观的并发控制和模式实施(结合发展模式的能力)确保原子性和一致性。

深入了解 DeltaLog

当用户创建 Delta Lake 表时,该表的事务日志会自动在子目录中创建_delta_log当用户修改表时,每个提交都作为 JSON 文件按升序写入子目录_delta_log,即000000.json000001.json000002.jsonon。


pasted image 0 (52).png


假设我们从数据文件1.parquet2.parquet该事务被添加到 DeltaLog 并保存为文件000000.json稍后,我们删除这些文件并添加一个新文件3.parquet这些操作被记录为一个新文件,000001.json.


pasted image 0 (53).png


1.parquet添加和之后2.parquet,它们被删除。事务日志包含这两个操作,即使它们相互否定。Delta Lake 保留所有原子提交以启用完整的审计历史和时间旅行功能,向用户显示表在特定时间点的外观。此外,在运行VACUUM作业之前,文件不会从存储中快速删除。MinIO版本控制提供了另一层防止意外删除的保证。

Delta Lake 和 MinIO 的耐用性

Delta Lake 通过将表和事务日志存储在持久性介质上来实现持久性。文件永远不会被覆盖,必须主动删除。写入存储的所有数据更改在发生时以原子方式提供给用户。部分和损坏的文件已成为过去。Delta Lake 不会在 RAM 中长时间保存表和日志,而是将它们直接写入 MinIO。只要提交数据记录在 DeltaLog 中并将 JSON 文件写入存储桶,数据就可以在系统或作业崩溃时持久保存。

MinIO 通过多种机制保证表及其组件写入后的持久性:

  • 擦除编码将数据文件拆分为数据和奇偶校验块并对其进行编码,以便即使部分编码数据不可用,也可以恢复主要数据。水平可扩展的分布式存储系统依靠擦除编码通过跨多个驱动器和节点保存编码数据来提供数据保护。如果驱动器或节点发生故障或数据损坏,可以从保存在其他驱动器和节点上的块中重建原始数据。

  • Bit Rot Protection实时捕获并修复损坏的对象,以消除这种对数据持久性的无声威胁

  • Bucket 和 Object Immutability使用对象锁定、保留和其他治理机制的组合来保护保存到 MinIO 的数据不被删除或修改。写入 MinIO 的对象永远不会被覆盖。

  • 桶和对象版本控制进一步保护对象。MinIO 维护每个对象的每个版本的记录,即使它被删除,使您能够回到过去(很像 Delta Lake 的时间旅行)。版本控制是数据生命周期管理的一个关键组成部分,它允许管理员在层之间移动存储桶,例如将 NVMe 用于性能密集型工作负载,并设置版本的到期日期,以便将它们从系统中清除以提高存储效率。

MinIO 使用加密保护 Delta Lake 表,并结合使用 IAM 和基于策略的访问控制来管理对它们的访问。MinIO使用 AES-256-GCM、ChaCha20-Poly1305 和 AES-CBC 等现代行业标准加密算法,使用 TLS 加密传输中的数据和使用粒度对象级加密的驱动器上的数据。MinIO 集成了外部身份提供者,例如 ActiveDirectory/LDAP、Okta 和 IAM 的 Keycloak。然后,用户和组在尝试访问 Delta Lake 表时受制于与 AWS IAM 兼容的 PBAC。

Delta Lake 和 MinIO 教程

本节介绍如何使用单集群模式在 MinIO 上快速开始读写 Delta 表。

先决条件

  1. 下载并安装Apache Spark。

  2. 下载并安装MinIO。记录 IP 地址、TCP 端口、访问密钥和秘密密钥。

  3. 下载并安装MinIO 客户端。

  4. 需要以下 jar 文件。您可以将 jar 复制到 Spark 机器上的任何所需位置,例如/home/spark.

  5. Hadoop - hadoop-aws-2.6.5.jar- Delta Lake 需要包org.apache.hadoop.fs.s3a.S3AFileSystem中的类hadoop-aws,它实现了 Hadoop 的FileSystemS3 API。确保此包的版本与构建 Spark 的 Hadoop 版本相匹配。

  6. AWS-aws-java-sdk-1.7.4.jar

使用 Delta Lake 设置 Apache Spark

使用 Delta Lake 启动 Spark shell(Scala 或 Python)并以交互方式运行代码片段。

在斯卡拉:

bin/spark-shell --packages io.delta:delta-core_2.12:1.2.1 --conf "spark.sql.extensions=io.delta.sql.DeltaSparkSessionExtension" --conf "spark.sql.catalog.spark_catalog=org.apache.spark.sql.delta.catalog.DeltaCatalog"

在 Apache Spark 上配置 Delta Lake 和 AWS S3

运行以下命令以启动带有 Delta Lake 和 S3 支持 MinIO 的 Spark shell:

bin/spark-shell \
--packages io.delta:delta-core_2.12:1.2.1,org.apache.hadoop:hadoop-aws:3.3.1 \

 
--conf spark.hadoop.fs.s3a.access.key=<your-MinIO-access-key> \
--conf spark.hadoop.fs.s3a.secret.key=<your-MinIO-secret-key>

 --conf "spark.hadoop.fs.s3a.endpoint=<your-MinIO-IP:port> \

 --conf "spark.databricks.delta.retentionDurationCheck.enabled=false" \

 --conf "spark.sql.extensions=io.delta.sql.DeltaSparkSessionExtension" \

 --conf "spark.sql.catalog.spark_catalog=org.apache.spark.sql.delta.catalog.DeltaCatalog"



在 MinIO 中创建一个桶

使用 MinIO 客户端为 Delta Lake 创建一个桶:

mc alias set minio http://<your-MinIO-IP:port> <your-MinIO-access-key>  <your-MinIO-secret-key>

mc mb minio\delta-lake


在 MinIO 上创建一个测试 Delta Lake 表

尝试一下并使用 Scala 创建一个简单的 Delta Lake 表:

// Create a Delta table on MinIO:
spark.range(500).write.format("delta").save("s3a://delta-lake/demo1")

您将看到一些输出表明 Spark 已成功写入表。

打开浏览器,使用您的访问密钥和秘密密钥登录 MinIO http://您将在存储桶中看到 Delta Lake 表:


image (2).png


用于数据湖上高性能 ACID 事务的 MinIO 和 Delta Lake

MinIO 和 Delta Lake 的结合使企业能够拥有一个多云数据湖,作为统一的单一事实来源。查询和更新 Delta Lake 表的能力为企业提供了对其业务和客户的丰富见解。各种团体访问 Delta Lake 表以进行他们自己的分析或机器学习计划,知道他们的工作是安全的并且数据是及时的。  

要深入了解,请下载 MinIO并亲自查看或在任何公共云上启动一个市场实例。你有问题吗?在Slack上或通过 hello@min.io提问


上一篇 下一篇