创建 Azure Databricks 兼容的 JAR

本页介绍如何创建与 Azure Databricks 工作区兼容的 Scala 或 Java 代码的 JAR。

概括而言,JAR 必须满足以下兼容性要求:

  • Java 开发工具包 (JDK) 版本与 Databricks 群集计算中的 JDK 版本匹配。

  • 在 Scala 方面,你的 Scala 版本与 Databricks 群集计算中的 Scala 版本相匹配。

  • Databricks Connect 添加为依赖项,并与 Databricks 群集上运行的版本匹配,或者 Spark 依赖项与 Databricks 环境兼容。

  • 要编译的本地项目打包为单个 JAR,并包含所有未生成的依赖项。 或者,可以将它们添加到环境或群集。

  • JAR 文件中的代码与 Spark 会话或上下文正确交互。

  • 对于标准计算,使用的所有 JAR 都会添加到 允许列表中

Databricks Connect 和 Databricks Runtime 版本控制

创建 JAR 以在 Azure Databricks 中运行时,了解如何调用 Spark API 以及要调用的 API 版本很有帮助。

Databricks Connect

Databricks Connect 实现 Spark Connect 体系结构,该体系结构分隔客户端和服务器组件。 这种分离允许有效地共享群集,同时通过行筛选器和列掩码等措施完全强制实施 Unity Catalog 治理。 但是,标准访问模式下的 Unity Catalog 群集存在一些限制,例如缺少对 Spark 上下文和 RDD 等 API 的支持。 Limtations 列在 标准计算要求和限制中。

Databricks Connect 提供对所有 Spark 功能(包括 Spark Connect)的访问权限,并且包含在标准计算中。 对于这些计算类型,需要 Databricks Connect,因为它提供了所有必要的 Spark API。

Databricks Runtime

Databricks Runtime 在 Azure Databricks 管理的计算上运行。 它基于 Spark,但包括性能改进和其他增强功能,以便于使用。

在标准计算中,Databricks Connect 提供调用在计算上运行的 Databricks Runtime 的 API。 在专用计算中,针对由 Copmute 上的 Databricks Runtime 支持的 Spark API 进行编译。

查找计算的正确版本

若要编译兼容的 JAR 文件,必须知道计算运行的 Databricks Connect 和 Databricks Runtime 的版本。

计算类型 如何查找正确的版本
标准模式下的计算 使用 Databricks Runtime 并提供 Databricks Connect 来调用 API。 若要查找您的计算环境中的 Databricks Runtime 版本,
  • 在工作区中,单击“云”图标。在侧边栏中选择Compute,然后选择您的计算资源。 Databricks Runtime 版本显示在配置详细信息中。 Databricks Connect 版本的主要版本值和次要版本值与 Databricks Runtime 版本的主要版本值和次要版本值匹配。
专用模式下的计算 使用 Databricks Runtime,并允许直接针对 Spark API 进行编译。
若要查找计算群集的 Databricks Runtime 版本,请执行以下作:
  • 在工作区中,单击“云”图标。在侧边栏中选择Compute,然后选择您的计算资源。 Databricks Runtime 版本显示在配置详细信息中。

JDK 和 Scala 版本

生成 JAR 时,用于编译代码的 Java 开发工具包(JDK)和 Scala 版本必须与计算上运行的版本匹配。

对于标准计算,请使用 Databricks Connect 版本查找兼容的 JDK 和 Scala 版本。 请参阅 版本支持矩阵

如果使用专用计算,则必须在计算上匹配 Databricks Runtime 的 JDK 和 Scala 版本。 Databricks Runtime 发行说明版本和每个 Databricks Runtime 版本的兼容性的系统环境部分包括正确的 Java 和 Scala 版本。 例如,对于 Databricks Runtime 17.3 LTS,请参阅 Databricks Runtime 17.3 LTS

注释

使用与计算机 JDK 版本或 Scala 版本不匹配的 JDK 或 Scala 版本可能会导致意外行为或阻止代码运行。

依赖关系

必须在生成文件中正确设置依赖项。

Databricks Connect 或 Apache Spark

对于标准计算,Databricks 建议添加对 Databricks Connect 的依赖项,而不是 Spark 来生成 JAR。 Databricks Runtime 与 Spark 不同,包括性能和稳定性改进。 Databricks Connect 提供 Azure Databricks 中提供的 Spark API。 若要包括 Databricks Connect,请添加依赖项:

Java

在 Maven pom.xml 文件中:

<dependency>
  <groupId>com.databricks</groupId>
  <artifactId>databricks-connect_2.13</artifactId>
  <version>17.0.2</version>
</dependency>

Scala

build.sbt 文件中:

libraryDependencies += "com.databricks" %% "databricks-connect" % "17.0.2"

注释

Databricks Connect 版本必须与群集 Databricks Runtime 中包含的版本匹配。

Databricks 建议使用 Databricks Connect。 如果不想使用 Databricks Connect,请针对 spark-sql-api 编译。 将此特定的 Spark 库添加到依赖项,但不包括 JAR 中的库。 在生成文件中,将依赖项的范围配置为 provided

Java

在 Maven pom.xml 文件中:

<dependency>
  <groupId>org.apache.spark</groupId>
  <artifactId>spark-sql-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

Scala

build.sbt 文件中:

libraryDependencies += "org.apache.spark" %% "spark-sql-api" % "4.0.1" % "provided"

Spark 依赖项

对于标准计算,请勿在项目中包括任何其他 Spark 依赖项。 使用 Databricks Connect 提供所有必要的 Spark 会话 API。

经典计算服务和 Databricks Runtime 提供的库

如果在经典计算上运行(在专用模式或标准模式下),Databricks Runtime 包含许多常见库。 查找 Databricks Runtime 版本 Databricks Runtime 发行说明“系统环境”部分中包含的库和版本。 例如, Databricks Runtime 17.3 LTS 系统环境 部分列出了 Databricks Runtime 中可用的每个库的版本。

若要针对其中一个库进行编译,请使用该选项将其添加为依赖项 provided 。 例如,在 Databricks Runtime 17.3 LTS 中, protobuf-java 提供了库,可以使用以下配置对其进行编译:

Java

在 Maven pom.xml中:

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.25.5</version>
  <scope>provided</scope>
</dependency>

Scala

build.sbt中:

libraryDependencies += "com.google.protobuf" %% "protobuf-java" % "3.25.5" % "provided"

未提供的库

对于 Databricks Runtime 中不可用的库,可以在 JAR 中自行包含它们。 例如,若要在circe-core文件中包含build.sbt,请添加以下命令:

libraryDependencies += "io.circe" %% "circe-core" % "0.14.10"

打包为单个 JAR

Databricks 建议将应用程序和所有依赖项打包到单个 JAR 文件中,也称为 über 或胖 JAR。 对于 sbt,请使用 sbt-assembly,对于 Maven,请使用 maven-shade-plugin。 有关详细信息,请参阅官方 Maven 着色插件sbt-assembly 文档。

或者,可以将依赖项安装为群集范围的库。 有关详细信息,请参阅计算范围的库。 如果在群集上安装库,代码中的依赖项应包含 provided 关键字,以避免在 jar 中打包库。

注释

对于安装为 Unity Catalog 标准集群库的 Scala JAR,JAR 库中的类必须位于命名包中,例如 com.databricks.MyClass这样的命名包,否则在导入库时会发生错误。

在代码中使用 Spark 会话

在作业中运行 JAR 时,必须使用 Azure Databricks 为作业提供的 Spark 会话。 以下代码展示了如何从您的代码中访问会话:

Java

SparkSession spark = SparkSession.builder().getOrCreate();

Scala

val spark = SparkSession.builder().getOrCreate()

确保 JAR 已列入允许列表(标准计算)

出于安全原因,标准访问模式要求管理员将 JAR 库的 Maven 坐标和路径添加到允许列表。 请参阅在采用标准访问模式(以前称为“共享访问模式”)的计算上将库和初始化脚本加入允许列表

建议:使用 try-finally 块进行作业清理

如果想要让代码在作业结束时可靠地运行,例如,若要清理作业期间创建的临时文件,请使用块 try-finally 。 请勿使用关闭挂钩,因为这些挂钩不会在作业中可靠运行。

假设有一个由两部分组成的 JAR:

  • jobBody(),包含作业的主要部分。
  • jobCleanup() 必须在 jobBody() 之后执行,不管该函数是成功还是返回了异常。

例如,jobBody() 创建表,而 jobCleanup() 会删除这些表。

若要确保调用清理方法,安全的方法是在代码中放置一个 try-finally 块:

try {
  jobBody()
} finally {
  jobCleanup()
}

不应该尝试使用 或以下代码进行清理:

// Do NOT clean up with a shutdown hook like this. This will fail.
val cleanupThread = new Thread { override def run = jobCleanup() }
Runtime.getRuntime.addShutdownHook(cleanupThread)

由于 Spark 容器的生存期在 Azure Databricks 中的管理方式,shutdown 挂钩的运行并不可靠。

读取作业参数

使用 JSON 字符串数组向 JAR 任务传递参数。 若要访问这些参数,请检查传入到 String 函数中的 main 数组。

有关参数的更多详细信息,请参阅 参数化任务

生成 JAR

以下步骤介绍如何使用 Scala 或 Java 创建和编译简单的 JAR 文件,以在 Azure Databricks 中工作。

要求

本地开发环境必须具有以下条件:

  • Java 开发工具包 (JDK) 17。
  • sbt (对于 Scala JAR)。
  • Databricks CLI 版本 0.218.0 或更高版本。 若要检查安装的 Databricks CLI 版本,请运行命令 databricks -v。 要安装 Databricks CLI,请参阅《安装或更新 Databricks CLI》。
  • Databricks CLI 身份验证使用配置文件 DEFAULT 进行配置。 若要配置身份验证,请参阅 “配置对工作区的访问权限”。

创建 Scala JAR

  1. 运行以下命令以创建新的 Scala 项目:

    > sbt new scala/scala-seed.g8
    

    出现提示时,输入项目名称,例如 my-spark-app

  2. 将你的 build.sbt 文件的内容替换为以下内容。 选择计算所需的 Scala 和 Databricks Connect 版本。 请参阅 依赖项

    scalaVersion := "2.13.16"
    libraryDependencies += "com.databricks" %% "databricks-connect" % "17.0.1"
    // other dependencies go here...
    
    // to run with new jvm options, a fork is required otherwise it uses same options as sbt process
    fork := true
    javaOptions += "--add-opens=java.base/java.nio=ALL-UNNAMED"
    
  3. 编辑或创建 project/assembly.sbt 文件,并添加以下行:

    addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1")
    
  4. src/main/scala/example/DatabricksExample.scala中创建主类:

    package com.examples
    
    import com.databricks.connect.DatabricksSession
    import org.apache.spark.sql.{SparkSession}
    
    object SparkJar {
      def main(args: Array[String]): Unit = {
        val spark: SparkSession = DatabricksSession.builder().getOrCreate()
    
        // Prints the arguments to the class, which
        // are job parameters when run as a job:
        println(args.mkString(", "))
    
        // Shows using spark:
        println(spark.version)
        println(spark.range(10).limit(3).collect().mkString(" "))
      }
    }
    
  5. 若要生成 JAR 文件,请运行以下命令:

    > sbt assembly
    

创建 Java JAR

  1. 为 JAR 创建文件夹。

  2. 在文件夹中,创建包含以下内容的文件 PrintArgs.java

    import java.util.Arrays;
    
    public class PrintArgs {
      public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
      }
    }
    
  3. 编译 PrintArgs.java 文件,以创建 PrintArgs.class 文件:

    javac PrintArgs.java
    
  4. (可选)运行编译的程序:

    java PrintArgs Hello World!
    
    # [Hello, World!]
    
  5. 在文件夹中,创建一个 pom.xml 文件,并添加以下代码以启用 Maven 阴影。

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>3.6.0</version>
          <executions>
            <execution>
              <phase>package</phase>
              <goals><goal>shade</goal></goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    
  6. 在 JAR 文件夹中,创建一个名为META-INF的文件夹。

  7. META-INF 文件夹中,创建名为 MANIFEST.MF 的文件,包含以下内容。 请务必在此文件末尾添加一个新行:

    Main-Class: PrintArgs
    
  8. 从你的 JAR 文件夹,创建一个名为 PrintArgs.jar 的 JAR:

    jar cvfm PrintArgs.jar META-INF/MANIFEST.MF *.class
    
  9. (可选)若要对其进行测试,请运行 JAR:

    java -jar PrintArgs.jar Hello World!
    
    # [Hello, World!]
    

    注释

    如果遇到错误“no main manifest attribute, in PrintArgs.jar”,请务必在 MANIFEST.MF 文件的末尾添加换行符,然后再次尝试创建并运行 JAR。

后续步骤