在本章中,我们将深入探讨Iceberg目录。您已经了解目录是Iceberg的关键组件,它确保多个读写者的一致性,并发现环境中可用的表。在本章中,我们将讨论:
- 目录的一般要求,以及推荐用于生产环境的附加要求
- 不同目录实现的优缺点,以及如何配置Spark以使用目录
- 在什么情况下您可能需要考虑迁移目录
- 如何从一个目录迁移到另一个目录
Iceberg目录的要求
Iceberg提供了一个目录接口,该接口需要实现一组功能,主要包括列出现有表、创建表、删除表、检查表是否存在以及重命名表。作为一个接口,它有多种实现,包括Hive Metastore、AWS Glue和文件系统目录(如Hadoop)。除了需要实现接口定义的功能外,作为Iceberg目录实现的主要高级要求是将表路径(例如,db1.table1)映射到具有表当前状态的元数据文件的文件路径。
由于这是一个通用要求,并且每个系统在存储数据方面存在固有差异,不同的目录实现这种映射的方式各不相同。例如,对于文件系统作为目录,在表的元数据文件夹中有一个名为version-hint.text的文件,其中包含当前元数据文件的版本号。对于Hive Metastore作为目录,Hive Metastore中的表条目有一个名为location的表属性,用于存储当前元数据文件的位置。
虽然这些是将目录实现用作Iceberg目录的最低要求,但在功能上能够使用目录和目录被推荐用于生产环境之间存在区别。这个区别在于确保当有多个并发作业写入同一张表时不会发生数据丢失。对于开发和实验目的,这一要求并不是必要的。然而,在生产环境中,数据丢失显然会对业务产生巨大影响。
Iceberg目录在生产环境中使用的主要要求是它必须支持更新当前元数据指针的原子操作。这是为了确保所有读写者在同一时间点看到表的相同状态,并且当有两个并发写入者时,第二个提交的写入者不会覆盖第一个写入者的更改,导致数据丢失。
目录比较
在本节中,我们将介绍几种更为流行的Iceberg目录。对于每种目录,我们将讨论目录如何将表路径映射到该表当前元数据文件的位置、目录的优缺点、适用场景以及如何配置Apache Spark以使用该目录。 比较不同目录的主要维度包括:
- 是否推荐用于生产环境
- 是否需要外部系统,以及该外部系统是自托管还是托管服务(或两者皆可)
- 是否具有广泛的引擎和工具兼容性
- 是否支持多表和多语句事务
- 是否与云无关(即云平台无关性)
Hadoop目录
最容易开始使用Iceberg的目录是Hadoop目录。这是因为它不需要任何外部系统或进程。尽管其名称为Hadoop目录,它实际上可以在任何文件系统上运行(或类似文件系统的存储,如云对象存储),包括Hadoop分布式文件系统(HDFS)、Amazon简单存储服务(Amazon S3)、Azure数据湖存储(ADLS)和Google云存储(GCS)。
Hadoop目录的核心功能是通过列出表的元数据目录的内容,根据文件系统中每个文件列出的时间戳选择最近写入的元数据文件,从而将表路径映射到其当前元数据文件。通常,引擎会在表的元数据文件夹中写入一个名为version-hint.txt的文件,其中包含一个数字,工具或引擎使用该数字通过名称检索相应的元数据文件,例如v{n}.metadata.json。
Hadoop目录的优缺点
优点:
- Hadoop目录的主要优点是不需要任何外部系统来运行。它只需要一个文件系统,从而降低了开始使用Iceberg的门槛。
缺点:
-
Hadoop目录的一个主要缺点是它不推荐用于生产环境。有几个原因:
- 首先,它要求文件系统提供一个原子性的文件/对象重命名操作,以防止并发写入时的数据丢失。一些文件系统和对象存储支持这一点,但并非所有都支持。例如,ADLS和HDFS提供原子性重命名操作,因此在并发写入同一表时不会导致数据丢失,但S3不支持。对于S3,可以利用DynamoDB表来实现所需的原子性,以防止并发写入时的数据丢失。然而,此时你已经在使用一个外部系统(DynamoDB本身也支持作为Iceberg目录),因此不如不使用Hadoop目录。
- 其次,当系统配置为使用Hadoop目录作为源时,只能使用一个仓库目录,因为它依赖于仓库位置来列出表。例如,如果使用云对象存储如S3或ADLS,则只能使用一个桶。如果希望在环境中为一组表使用多个桶,则必须为每个桶配置一个单独的源。
- 第三,当你需要列出命名空间(即数据库)和/或表时,可能会遇到性能问题,尤其是在有大量命名空间和表的情况下。这是因为列出命名空间和表是通过对文件系统进行列出操作来完成的。例如,在使用S3并且有大量命名空间和/或表的情况下,这可能需要一段时间。
- 最后,无法从目录中删除表或删除目录中的引用同时保留数据。如果删除表而不删除数据,可以在需要时撤销操作(类似于时光旅行)。例如,在Spark SQL中,如果使用除Hadoop目录以外的目录,运行DROP TABLE 只会从目录中删除引用,但不会删除数据。如果你确定数据不需要被撤销,可以运行DROP TABLE PURGE来删除表和数据。但如果使用Hadoop目录,即使删除version-hint.txt文件,由于warehouse_dir/namespace1/table1/metadata中的文件存在,表仍存在于目录定义中。通过列出元数据目录并选择最近创建的元数据文件(根据文件系统中的时间戳),仍然可以检索到当前元数据文件。
Hadoop目录的使用场景
鉴于这些优缺点,有几种情况你可以考虑使用Hadoop目录。一个非常常见的情况是,当你是Iceberg的新手并希望快速开始时。由于你已经有一个分布式文件系统,你只需使用Hadoop目录,不需要其他系统或基础设施。此外,正如本章稍后讨论的那样,迁移目录既快速又简单,因此你可以先使用Hadoop目录,在准备好进入生产环境时迁移到生产就绪的目录。另一个情况是,如果你在实验或测试/开发环境中使用,那里不会有并发写入同一表的情况,或者即使有,也不会造成数据丢失问题。
配置Spark以使用Hadoop目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过Hadoop目录读写Iceberg表:
spark-sql --packages org.apache.iceberg:iceberg-spark-runtime-3.3_2.12:0.14.0\
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.type=hadoop \
--conf spark.sql.catalog.my_catalog1.warehouse=<protocol>://<path>
Hive目录
Hive目录是用于Iceberg目录的一个流行实现。它通过在Hive Metastore中的表条目使用location表属性将表路径映射到其当前元数据文件。该属性的值是文件系统中表的当前元数据文件的绝对路径。
Hive目录的优缺点
优点:
- Hive目录的主要优点是与各种引擎和工具兼容,因为许多系统已经支持连接到Hive Metastore,尽管最初是为了以Hive表格式排列的表。此外,它是云无关的,这也是一个优势。
缺点:
- Hive目录有两个缺点。首先是需要自行运行一个额外的服务。与其他一些目录不同,用于Hive目录的Hive Metastore需要用户设置和管理。不过,也有一些托管选项可用,如Amazon EMR。第二个缺点是它不支持多表事务。多表事务是数据库中的一项关键功能,支持对涉及多个表的一个或多个操作提供一致性和原子性。它们的主要意义在于能够在环境中保持数据一致性,这是维护数据质量和数据信任的关键。第10章会更深入地讨论多表事务。
Hive目录的使用场景
选择Hive目录的主要情况是,如果你的环境中已经运行了Hive Metastore,并计划继续使用它。然而,请记住,如果你需要多表事务,Hive目录是不支持的。
配置Spark以使用Hive目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过Hive目录读写Iceberg表:
spark-sql --packages org.apache.iceberg:iceberg-spark-runtime-3.3_2.12:0.14.0\
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.type=hive \
--conf spark.sql.catalog.my_catalog1.uri=thrift://<metastore-host>:<port>
AWS Glue目录
AWS Glue目录是Iceberg目录的另一种实现。它利用AWS Glue数据目录作为集中元数据存储库来跟踪Iceberg表元数据。它通过在Glue中的表条目中使用名为metadata_location的表属性将表路径映射到其当前元数据文件。该属性的值是文件系统中元数据文件的绝对路径。
AWS Glue目录的优缺点
优点:
- 使用AWS Glue作为Iceberg目录有多个优势。一个重要的优势是AWS Glue是一项托管服务,因此与管理自己的元数据存储(如Hive)相比,它减少了操作开销。另一个优势是由于它是AWS的原生服务,因此与其他AWS服务具有紧密集成。
缺点:
- 然而,AWS Glue目录也有其缺点。与Hive目录类似,它不支持多表事务。此外,它是特定于AWS生态系统的,这意味着在多云环境中操作并使用AWS Glue作为Iceberg目录可能会使部署复杂化。
AWS Glue目录的使用场景
如果你在AWS服务中投入较多、不需要多云解决方案和/或需要托管目录解决方案,AWS Glue目录是一个不错的选择。由于不需要预先配置任何内容,它还可以帮助你快速开始使用Iceberg。但请记住,如果你的数据处理场景需要多表事务,这个目录可能不适合。
配置Spark以使用AWS Glue目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过AWS Glue目录读写Iceberg表:
spark-sql --packages "org.apache.iceberg:iceberg-spark-runtime-x.x_x.xx:x.x.x,software.amazon.awssdk:bundle:x.xx.xxx,software.amazon.awssdk:url-connection-client:x.xx.xxx" \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.warehouse=s3://<path> \
--conf spark.sql.catalog.my_catalog1.catalog-impl=org.apache.iceberg.aws.glue.GlueCatalog \
--conf spark.sql.catalog.my_catalog1.io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--conf spark.hadoop.fs.s3a.access.key=$AWS_ACCESS_KEY \
--conf spark.hadoop.fs.s3a.secret.key=$AWS_SECRET_ACCESS_KEY
Nessie目录
Project Nessie是Iceberg目录的另一种选择。在Nessie中,通过在Nessie中存储的表条目中的表属性metadataLocation将表路径映射到其当前元数据文件。该属性的值是表当前元数据文件的绝对路径。
Nessie目录的优缺点
优点:
- Project Nessie的一个优点是它为数据湖引入了类似Git的体验,并实现了“数据即代码”的概念,这意味着数据及其相关元数据可以像源代码一样进行版本控制和管理。这对于数据工程和数据科学工作流程尤其有价值,其中安全更改、可重复性和可追溯性至关重要。
- 另一个优点是,使用Project Nessie作为Iceberg目录可以实现多表和多语句事务,就像数据仓库一样。
- 第三个优点是,它是云无关的,因此无论你今天是多云环境,明天将是多云环境,还是希望减少云供应商锁定,都可以使用同一个目录。
缺点:
- Project Nessie的两个缺点之一是并非所有引擎和工具都支持Nessie作为目录。截至撰写本文时,Spark、Flink、Dremio、Presto、Trino和PyIceberg支持Nessie作为目录。
- 另一个缺点是你必须自己运行基础设施,就像在Hive Metastore中一样。不过,与AWS Glue提供托管版本(或至少兼容版本,看起来像Hive Metastore)类似,Dremio也提供Project Nessie的托管版本。
Nessie目录的使用场景
如果你需要多表/多语句事务,想利用数据即代码的范式,和/或希望云无关,Nessie是一个很好的选择。
配置Spark以使用Project Nessie目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过Project Nessie作为Iceberg目录来读写Iceberg表:
spark-sql --packages
"org.apache.iceberg:iceberg-spark-runtime-x.x_x.xx:x.x.x,org.projectnessie:nessie-spark-extensions-x.x_x.xx:x.xx.x,software.amazon.awssdk:bundle:x.xx.xxx,software.amazon.awssdk:url-connection-client:x.xx.xxx" \
--conf spark.sql.extensions="org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions,org.projectnessie.spark.extensions.NessieSparkSessionExtensions" \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.catalog-impl=org.apache.iceberg.nessie.NessieCatalog \
--conf spark.sql.catalog.my_catalog1.uri=$NESSIE_URI \
--conf spark.sql.catalog.my_catalog1.ref=main \
--conf spark.sql.catalog.my_catalog1.authentication.type=BEARER \
--conf spark.sql.catalog.my_catalog1.authentication.token=$TOKEN \
--conf spark.sql.catalog.my_catalog1.warehouse=<protocol>://<path> \
--conf spark.sql.catalog.my_catalog1.io-impl=org.apache.iceberg.aws.s3.S3FileIO
REST目录
顾名思义,REST目录利用RESTful服务提供商作为Iceberg目录。这种方法提供了有趣的灵活性,因为REST目录是一个接口,而不是特定的实现,不像大多数其他目录。实现REST目录接口的服务可以选择以任何方式存储表路径到其当前元数据文件的映射。它甚至可以将其存储在本节中提到的其他目录之一中。
REST目录的优缺点
优点:
- REST目录的几个优点之一是它比其他目录需要更少的包和依赖项,简化了部署和管理。这是因为它的核心只是使用标准的HTTP通信。
- 另一个优点是它提供的灵活性,因为它可以由任何能够处理RESTful请求和响应的服务提供,并且服务的数据存储可以是许多不同的东西。
- 第三个优点是REST目录支持多表事务,为跨多个表的复杂操作提供了灵活性。
- 最后一个优点是它是云无关的,因此无论你今天是多云环境,明天将是多云环境,还是希望减少云供应商锁定,都可以使用同一个目录。
缺点:
- REST目录的三个主要缺点之一是你必须运行一个进程来处理和响应引擎和工具的REST调用。如果你在生产中运行它,你还需要运行或使用一个额外的数据存储服务来存储状态。
- 第二个缺点是,截至本文撰写时,没有支持REST目录端点的公共实现的后端服务,这意味着你需要自己编写。
- 这两个缺点的一个替代方案是使用提供托管服务的REST目录,例如Tabular。
- 第三个缺点是并非所有引擎和工具都支持REST目录。截至本文撰写时,Spark、Trino、PyIceberg和Snowflake支持REST目录。
REST目录的使用场景
如果你正在寻找一个灵活的、可定制的解决方案,可以与各种后端数据存储集成,或者你需要进行多表事务的能力,和/或你希望实现云无关性,REST目录是一个不错的选择。
配置Spark以使用REST目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过REST目录来读写Iceberg表:
spark-sql --packages org.apache.iceberg:iceberg-spark-runtime-3.3_2.12:0.14.0\
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.type=rest \
--conf spark.sql.catalog.my_catalog1.uri=http://<host>:<port>
JDBC目录
JDBC目录利用Java数据库连接(JDBC)兼容的数据存储作为Iceberg的目录接口,如果你的数据位于支持JDBC的数据库(如MySQL或PostgreSQL)中,这将是一个多功能的选择。请注意,JDBC连接的数据库必须支持原子事务。
JDBC目录通过在JDBC兼容的数据库中设置一个名为metadata_location的表属性来映射表路径到其当前元数据文件,存储表当前元数据文件的位置。
JDBC目录的优缺点
优点:
- 使用JDBC目录有多个优点。首先,它易于上手。如果你有一个JDBC兼容的数据存储,你已经有了使用JDBC目录的必要基础设施。常见的例子包括MySQL和PostgreSQL。即使你没有现成的数据库,云提供商也使其轻松启动,例如Amazon RDS和Azure Database for MySQL/PostgreSQL。
- 另一个优点是,这些数据库(特别是云托管的数据库)使得高可用性变得简单,确保即使主数据库实例宕机,你的数据仍然可以访问和安全。
- 第三个优点是它是云无关的,因此无论你今天是多云环境,明天将是多云环境,还是希望减少云供应商锁定,都可以使用同一个目录。
缺点:
- JDBC目录有两个主要缺点。首先,它不支持多表事务。
- 其次,它要求所有的引擎和工具都要在其部署中打包JDBC驱动程序或能够动态拉取一个JDBC驱动程序,从而增加了部署的依赖性。
JDBC目录的使用场景
如果你已经有一个JDBC兼容的数据库在运行或计划使用云提供商提供的数据库服务(如Amazon RDS),你可能会选择JDBC目录。如果你的环境需要高可用性和/或你希望实现云无关性,这也是一个不错的选择。
配置Spark以使用JDBC目录
以下代码片段展示了如何启动Spark SQL shell,在其中可以使用my_catalog1通过JDBC目录来读写Iceberg表:
spark-sql --packages org.apache.iceberg:iceberg-spark-runtime-x.x_x.xx:x.x.x \
--conf spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.warehouse=<protocol>://<path> \
--conf spark.sql.catalog.my_catalog1.catalog-impl=org.apache.iceberg.jdbc.JdbcCatalog \
--conf spark.sql.catalog.my_catalog1.uri=jdbc:<protocol>://<host>:<port>/<database> \
--conf spark.sql.catalog.my_catalog1.jdbc.user=<username> \
--conf spark.sql.catalog.my_catalog1.jdbc.password=<password>
其他目录
请注意,除了这里介绍的目录实现之外,还有其他的目录实现(例如,内存中、DynamoDB、Snowflake)。然而,在这里,我们选择聚焦于最常见的目录,因为有很多其他的选择,几乎任何东西都可以作为Iceberg目录,只要它提供了“Iceberg目录的要求”中提到的功能即可。
目录迁移
Iceberg 表的绝大部分存储在数据湖存储中的一个优点是,从一个目录实例迁移到另一个目录实例或从一个目录类型迁移到另一个目录类型是一个非常轻量级的操作 —— 你只需要改变表路径到当前元数据文件的映射。然而,尽管操作本身很轻量,但像所有迁移一样,应该制定一个适当的计划来处理周围的复杂性,比如写作业以及你环境中的不同工具和应用程序。
能够轻松迁移目录有助于减轻供应商和目录系统锁定风险,并使你的数据未来更具备可移植性。如果有更好或更经济的解决方案出现,你可以轻松地进行切换,而无需太多麻烦。
有几种情况可能会考虑迁移目录。一种情况是,如果你一直在使用一个目录进行试验和/或评估 Iceberg,比如 Hadoop,以快速入门,但你希望在生产中使用另一个目录,那么你可能会考虑迁移。第二种情况是,如果你想要利用你当前目录没有的附加功能。第三种情况是,如果你要更改环境的位置。一个例子是,如果你在本地使用 Hive Metastore 从旧的 Hadoop 部署中,并且要迁移到 AWS 并希望使用 AWS Glue,因为它是一个托管的产品。请注意,这第三种情况需要额外考虑,因为你将会迁移数据。
迁移是轻量级的一个好处是你可以继续使用当前目录,在新目录中注册一组表,保留当前目录中的条目,并在新目录上进行测试。在这种情况下,请注意,新目录的条目将是过时的,使用当前目录对表进行的任何更改都会反映在新目录中。你不应该使用新目录更改表,因为当前目录的所有现有使用者都看不到这些更改。
有两种标准的迁移目录的方法。我们将接下来介绍它们。
使用 Apache Iceberg Catalog 迁移 CLI
Iceberg 目录迁移工具是一个 CLI,它是 Project Nessie 中的一个开源工具。为了保持清晰地强调 Iceberg 项目专注于表格式规范和引擎集成,Apache Iceberg 社区选择了维护一个与 Iceberg 存储库分开的工具的独立代码库。它可以在不需要复制数据的情况下批量迁移 Apache Iceberg 表从一个目录到另一个目录。该工具支持 Apache Iceberg 中所有常用的目录,如 AWS Glue、Nessie、Dremio Arctic、Hadoop、Hive、REST、JDBC 和任何自定义目录。
iceberg-catalog-migrator 目前提供了两个主要功能:迁移和注册。重要的是,这两个功能都不会创建数据副本。而且,它们都转移了表的整个历史记录,允许在迁移或注册后在新目录中进行时间旅行等功能。以下是 migrate 和 register 命令的摘要:
migrate migrate 命令促进了从原始(源)目录到新(目标)目录的 Iceberg 表的批量迁移。一旦迁移成功完成,表条目将不再存在于源目录中;它们实际上被移动到了目标目录中。
register register 命令允许您将来自源目录的 Iceberg 表包含(或注册)到目标目录中。与迁移操作不同,注册不涉及从源目录中删除表。因此,在成功注册后,表将同时存在于两个目录中。这种功能特别适用于进行迁移前验证测试或探索提供独特功能的新目录等任务,同时确保原始表保持完好。当使用 register 命令时,您需要确保不要从多个目录写入相同的表。这样做可能会导致缺少更新、数据丢失和潜在的表损坏。建议使用 migrate 命令来执行此任务,该命令在注册后自动从源目录中删除表,避免这些问题。或者,避免在注册后对来自源目录的表执行操作。
请注意,不建议在源目录中进行正在进行提交的表期间使用 CLI 工具。这是为了防止在目标目录中出现缺少更新、数据丢失和潜在的表损坏。在迁移期间,该工具捕获了表的特定状态(一个元数据文件),并将该状态用于注册到目标目录中。如果源目录表正在进行提交,新的提交将不会反映在目标目录中,从而危及您数据的完整性。采用批处理式的迁移方法通常是推荐的,使用正则表达式(例如,命名空间1中的所有表或命名空间1中名称以字母 a 开头的所有表)来进行。这种方法可以作为常规维护和停机过程的一部分,允许用户在此阶段避免写入数据,并暂停任何自动运行的作业。请注意,这些作业在重新开始运行之前需要重新指向新目录。另一种选择是拥有一个中间层的包装器,最初指向现有目录,将您的作业配置为指向该包装器,验证没有问题后执行迁移。迁移完成后,您的作业不需要更改;您只需要将包装器指向新目录即可。
以下是 CLI 工具的一个示例用法:
java -jar iceberg-catalog-migrator-cli-0.2.0.jar migrate \
--source-catalog-type GLUE \
--source-catalog-properties warehouse=s3a://bucket/gluecatalog/,io-
impl=org.apache.iceberg.aws.s3.S3FileIO \
--source-catalog-hadoop-conf
fs.s3a.secret.key=$AWS_SECRET_ACCESS_KEY,fs.s3a.access.key=$AWS_ACCESS_KEY_ID \
--target-catalog-type NESSIE \
--target-catalog-properties uri=http://localhost:19120/api/v1,ref=main,ware-
house=s3a://bucket/nessie/,io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--identifiers db1.nominees
执行此命令时,将从 AWS Glue 目录(由 --source-catalog-type 指定)中迁移表 db1.nominees(由 --identifiers 标志指定),该目录是根据 AWS 凭据(由 --source-catalog-hadoop-conf 设置指定)的 AWS 账户对应的。到运行在本地主机上端口 19120 上的 Nessie 目录(由 --target-catalog-type 指定),并且目录的 uri 属性(在 --target-catalog-properties 中指定)指定为 localhost。
使用引擎
迁移目录的第二种标准方法是使用诸如 Apache Spark 这样的引擎。在使用 Spark 时,可以使用一组 Spark SQL 过程。您需要配置源目录和目标目录,以便 Spark 会话可以使用这些过程。
例如,如果您想要将 Hadoop 目录作为源目录,将 AWS Glue 目录作为目标目录,您可以像这样配置 Spark SQL:
spark-sql --packages "org.apache.iceberg:iceberg-spark-runtime-x.x_x.xx:x.x.x,software.amazon.awssdk:bundle:x.xx.xxx,software.ama-zon.awssdk:url-connection-client:x.xx.xxx" \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.source_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.source_catalog1.type=hadoop \
--conf spark.sql.catalog.source_catalog1.warehouse=<protocol>://<path> \
--conf spark.sql.catalog.target_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.target_catalog1.warehouse=s3://<path> \
--conf spark.sql.catalog.target_catalog1.catalog-impl=org.apache.iceberg.aws.glue.GlueCatalog \
--conf spark.sql.catalog.target_catalog1.io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--conf spark.hadoop.fs.s3a.access.key=$AWS_ACCESS_KEY \
--conf spark.hadoop.fs.s3a.secret.key=$AWS_SECRET_ACCESS_KEY
执行此命令时,将启动一个配置好的 Spark SQL shell,允许在 Hadoop 目录(由 --conf spark.sql.catalog.source_catalog1.type 指定)中的输入位置(由 --conf spark.sql.catalog.source_catalog1.warehouse 指定)和 AWS Glue 目录之间迁移表(由 --conf spark.sql.catalog.target_catalog1.catalog-impl=org.apache.iceberg.aws.glue.GlueCatalog 指定),该目录对应于 AWS 凭据的 AWS 账户(由 --conf spark.hadoop.fs.s3a.access.key 和 --conf spark.hadoop.fs.s3a.secret.key 指定)。
请注意,执行此命令只会启动一个配置好的 Spark SQL shell,其中配置了两个目录(source_catalog1 和 target_catalog1),允许命令使用这些目录,而不是立即迁移表。在迁移表之间时,有两个主要过程需要考虑。我们将接下来介绍这些过程。
register_table()
register_table() Spark SQL 过程会使用源表的数据文件创建源表的轻量级副本。对目标目录表所做的任何更改都将在源目录表的目录中进行,但只要这些更改不会物理删除任何数据文件(例如,expire_snapshot()),就不会在源目录表中看到应用到目标目录中的表的更改。尽管如此,在这种情况下,不建议对目标目录中的表进行更改。
这种方法在验证迁移时不需要对目标目录的表进行任何更改时可能很有用。如果您想要迁移目录,但是希望在迁移前后保持数据湖存储中表的文件位置不变,这种方法也可能很有用。
请注意,此方法传输表的整个历史记录,因此在使用此过程后,可以执行历史操作,例如时间旅行,并通过系统表查看表的历史记录。
表 5-1. register_table() 过程的参数
| 参数名 | 是否必需 | 类型 | 描述 |
|---|---|---|---|
| table | 是 | 字符串 | 要注册的目标表名称 |
| metadata_file | 是 | 字符串 | 要注册为新目标表的当前元数据文件的元数据文件 |
表 5-2. register_table() 过程的输出
| 输出名称 | 类型 | 描述 |
|---|---|---|
| current_snapshot_id | 长整型 | 新注册的 Iceberg 表的当前快照 ID |
| total_records_count | 长整型 | 新注册的 Iceberg 表的总记录数 |
| total_data_files_count | 长整型 | 新注册的 Iceberg 表的总数据文件数 |
以下是基于前一部分中 Spark SQL shell 配置的 register_table 过程的示例用法:
CALL target_catalog.system.register_table(
'target_catalog.db1.table1', '/path/to/source_catalog_warehouse/db1/table1/metadata/xxx.json'
)
snapshot()
与 register_table() 类似,snapshot() Spark SQL 过程也会创建源表的轻量级副本,使用源表的数据文件。然而,与 register_table() 不同的是,对目标目录表所做的任何更改都将在目标表的表位置进行,这意味着对目标表所做的任何更改都不会影响源表。也就是说,对源表的任何更改都不会对目标表的用户可见,反之亦然。
这种方法可用于测试迁移,其中需要对目标表进行更改以进行验证,但您不希望使用源表的任何内容看到这些更改。目标目录表不拥有数据文件的另一个结果是,不允许在目标表上运行 expire_snapshots(),因为那将意味着删除源目录表拥有的数据文件。如果您想要将表的文件位置更改为新目录,这也很有用,因为随着时间的推移和更改,表的元数据和数据文件的大部分将位于目标目录表的位置。此外,如果您愿意,您可以在迁移后的某个时间点使用 rewrite_data_files() 更快地进行文件迁移(例如,从本地到云端,或从一个云到另一个云)。
请注意,这种方法会传输表的完整历史记录,因此在使用此过程后,可以执行诸如时间旅行和通过系统表查看表的历史记录等历史操作。
表 5-3. snapshot() 过程的参数
| 参数名称 | 是否必需 | 类型 | 描述 |
|---|---|---|---|
| source_table | 是 | 字符串 | 要创建快照的表的名称 |
| table | 是 | 字符串 | 要创建的新 Iceberg 表的名称 |
| location | 字符串 | 新表的表位置(默认委托给目录) | |
| properties | map<string, string> | 要添加到新创建的表中的属性 |
表 5-4. snapshot() 过程的输出
| 输出名称 | 类型 | 描述 |
|---|---|---|
| imported_files_count | Long | 添加到新表中的文件数量 |
以下是基于前面部分的 Spark SQL shell 配置的 snapshot() 过程的示例用法:
CALL target_catalog.system.snapshot(
'source_catalog.db1.table1',
'target_catalog.db1.table1'
)
总结
在本章中,我们详细探讨了Iceberg目录,着重研究了它们在维护多个读取器和写入器之间的一致性以及在发现给定环境中可用表格方面的关键作用。
我们审查了目录的基本要求,以及在生产环境中部署目录所需的附加条件。我们还全面比较了各种目录实现,详细说明了它们的优缺点,并解释了如何为每种目录配置Spark。此外,我们讨论了目录迁移,包括可能考虑迁移目录的情景,以及如何执行迁移的两种主要方法。
在第六章中,我们将亲自尝试在各种不同的工具中使用Apache Iceberg。