DBFS 和 Unity Catalog 的最佳做法

Unity Catalog 引入了许多新配置和概念,这些配置和概念的数据治理方式与 DBFS 完全不同。 本文概述了有关使用 Unity Catalog 外部位置和 DBFS 的多种最佳做法。

Databricks 建议不要在已启用 Unity Catalog 的 Azure Databricks 工作区中的大多数用例中使用 DBFS 和已装载云对象存储。 本文介绍一些应使用已装载云对象存储的场景。 请注意,Databricks 不建议将 DBFS 根与 Unity Catalog 结合使用,除非必须将存储在其中的文件或数据迁移到 Unity Catalog 中。

如何在已启用 Unity Catalog 的工作区中使用 DBFS?

DBFS 根是相关文件存储的默认位置,用于存储与在 Azure Databricks 工作区中执行的许多操作(包括在工作区范围的 hive_metastore 中创建托管表)关联的文件。 对 hive_metastore 中的表执行的操作使用旧数据访问模式,其中可能包括由 DBFS 管理的数据和存储凭据。

DBFS 如何在单用户访问模式下工作?

配置了单用户访问模式的群集对 DBFS 具有完全访问权限,包括 DBFS 根中的所有文件和装载数据。 DBFS 根和装载在此访问模式下可用,适合需要访问 Unity Catalog 数据集的 ML 工作负载。

Databricks 建议将服务主体与计划作业和单用户访问模式结合使用,用于需要访问由 DBFS 和 Unity Catalog 管理的数据的生产工作负载。

DBFS 如何在共享访问模式下工作?

共享访问模式将 Unity Catalog 数据治理与 Azure Databricks 旧表 ACL 相结合。 对 hive_metastore 中数据的访问权限仅对显式授予权限的用户可用。

若要直接使用 DBFS 与文件交互,必须授予 ANY FILE 权限。 由于 ANY FILE 让用户可绕过 hive_metastore 中的旧表 ACL 并访问 DBFS 管理的所有数据,因此 Databricks 建议在授予此特权时要谨慎。

请不要将 DBFS 与 Unity Catalog 外部位置一起使用

Unity Catalog 使用完整的云 URI 路径来标识托管对象存储目录上的授权,从而保护对外部位置中数据的访问。 DBFS 装载使用完全不同的数据访问模型,该模型完全绕过 Unity Catalog。 Databricks 建议不要在 DBFS 装载和 UC 外部卷之间重复使用云对象存储卷。

保护 Unity Catalog 托管存储

每个 Unity Catalog 元存储都有一个由 Azure Databricks 帐户管理员配置的对象存储帐户。 Unity Catalog 使用此位置存储 Unity Catalog 托管表的所有数据和元数据。

用于 Unity Catalog 元存储的存储帐户应:

  • 为 Unity Catalog 而新建。
  • 为 Unity Catalog 定义自定义标识策略。
  • 只能通过 Unity Catalog 进行访问。
  • 只能使用为 Unity Catalog 创建的标识访问策略进行访问。

将现有数据添加到外部位置

可以使用外部位置将现有存储帐户加载到 Unity Catalog 中。 为获得最大安全性,Databricks 建议仅在撤销所有其他存储凭据和访问模式时将存储帐户加载到外部位置。

不应将用作 DBFS 根的存储帐户加载为 Unity Catalog 中的外部位置。

Unity Catalog 文件系统访问会忽略群集配置

Unity Catalog 不遵循文件系统设置的群集配置。 这意味着使用 Unity Catalog 访问数据时,用于通过云对象存储配置自定义行为的 Hadoop 文件系统设置不起作用。

关于多个路径访问的限制

虽然通常可以同时使用 Unity Catalog 和 DBFS,但不能使用不同访问方法在同一命令或笔记本单元中引用等于或共享父/子关系的路径。

例如,如果在位置 a/b/chive_metastore 中定义了外部表 foo,并在 a/b/ 上的 Unity Catalog 中定义了外部位置,则以下代码将引发错误:

spark.read.table("foo").filter("id IS NOT NULL").write.mode("overwrite").save("a/b/c")

如果将此逻辑分解为两个单元格,则不会出现此错误:

df = spark.read.table("foo").filter("id IS NOT NULL")
df.write.mode("overwrite").save("a/b/c")