重要
Databricks 强烈建议使用声明性自动化捆绑包,而不是按照本页中所述手动生成和部署 JAR。 声明性自动化捆绑包可以轻松地从模板创建项目,该模板具有为无服务器配置的正确 Scala、JDK 和 Databricks Connect 版本,还可以将 JAR 简单部署到 Databricks 工作区。 请参阅 使用声明性自动化捆绑包生成 Scala JAR。
重要
无服务器 Scala 和 Java 作业位于 Public Preview中。
Java存档(JAR)包将Java或 Scala 代码打包到单个文件中。 本页介绍如何使用 Spark 代码创建 JAR,并将其部署为 无服务器计算上的 Lakeflow 作业。 可以使用 JAR 任务来部署 JAR 文件。
要求
若要生成 JAR,本地开发环境必须安装以下内容:
- sbt 1.11.7 或更高版本,用于 Scala JAR 包
- 用于 Java JAR 的 Maven 3.9.0 或更高版本
- 与 无服务器环境匹配的 JDK、Scala 和 Databricks Connect 版本。 请参阅 依赖项版本。
依赖项版本
重要
若要在不发生故障的情况下在无服务器计算上运行,JAR Scala 和 JDK 版本必须与运行时 Scala 和 JDK 版本完全匹配。 请参阅 Databricks Connect 版本。
此页上的示例使用 无服务器环境版本 4,因此此页面将创建一个 JAR:
- 针对 Scala 2.13 编译;每个依赖项都使用
_2.13后缀。 - 基于 JDK 17 编译,类文件版本为 61。
- 针对 Databricks Connect 17.3(用于无服务器计算的 Spark API 图面)编译。
- 仅使用公共 Spark API。 它既不使用 RDD,也不依赖 Spark 内部机制。 请参阅限制。
- 包含 JAR 中的所有依赖项,或将其作为无服务器环境库附加。 请参阅 “管理依赖项”。
局限性
无服务器计算使用 Spark Connect。 您的 JAR 基于一个公开暴露 Spark API 的轻量级客户端库运行,而 Spark 引擎本身则在服务器端运行。 绕过公共 API 的代码无法受益于 Catalyst 优化或 Photon 加速,即使在经典计算上也是如此。 基于 RDD 且依赖于内部的代码通常比等效的数据帧或 SQL 代码慢。
以下内容不可用:
- RDD API (
org.apache.spark.rdd.*) 和SparkContext/JavaSparkContext. 请改用SparkSession.builder().getOrCreate()以及 DataFrame/Dataset 操作。 - Spark 内部 API(
org.apache.spark.catalyst.*、、org.apache.spark.util.*org.apache.spark.sql.util.*、org.apache.spark.sql.internal.*)。 导入这些 API 的代码会因NoClassDefFoundError而失败。 重构为使用公开的 Spark API。 如果第三方库使用内部版本,请检查它是否发布与 Spark Connect 兼容的版本。 - 原生库(
.so、.dll、JNI)。 无服务器计算不允许将原生库写入文件系统。 在启动时解压原生二进制文件的库会因UnsatisfiedLinkError而失败。 Init 脚本不是解决方法。 如果有对应的 Java 版本,请使用它。
如果工作负荷需要上述任何一项,请改为在 标准或专用计算 上运行它。
步骤 1:生成 JAR
Scala
运行以下命令以创建 Scala 项目:
sbt new scala/scala-seed.g8出现提示时,输入项目名称,例如
my-spark-app。接下来,删除种子的存根文件并为源创建目录:
cd my-spark-app rm src/main/scala/example/Hello.scala rm src/test/scala/example/HelloSpec.scala rm project/Dependencies.scala mkdir -p src/main/scala/com/examples将你的
build.sbt文件的内容替换为下面的内容:name := "my-spark-app" // Set the dependency versions scalaVersion := "2.13.16" javacOptions ++= Seq("--release", "17") scalacOptions ++= Seq("-release", "17") libraryDependencies += "com.databricks" %% "databricks-connect" % "17.3.2" % "provided" // Your other dependencies go here. Use %% for Scala libraries so sbt picks the _2.13 artifact. // Fork a new JVM on run so our javaOptions are applied. fork := true javaOptions += "--add-opens=java.base/java.nio=ALL-UNNAMED"编辑或创建
project/plugins.sbt文件,并添加以下行:addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1")在
src/main/scala/com/examples/SparkJar.scala中创建主类:package com.examples import org.apache.spark.sql.SparkSession object SparkJar { def main(args: Array[String]): Unit = { val spark = SparkSession.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(" ")) } }若要生成 JAR 文件,请运行以下命令:
sbt assembly编译后的 JAR 会在
target/文件夹中创建,名称为my-spark-app-assembly-0.1.0-SNAPSHOT.jar。
Java
运行以下命令以创建 Maven 项目结构:
mkdir -p my-spark-app/src/main/java/com/examples cd my-spark-app在项目根目录中创建一个
pom.xml文件,并使用以下内容:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.examples</groupId> <artifactId>my-spark-app</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.release>17</maven.compiler.release> <scala.binary.version>2.13</scala.binary.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- Included on serverless compute. --> <dependency> <groupId>com.databricks</groupId> <artifactId>databricks-connect_${scala.binary.version}</artifactId> <version>17.3.2</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- Maven Shade Plugin - Creates a fat JAR with all non-provided dependencies. --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.6.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.examples.SparkJar</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>在
src/main/java/com/examples/SparkJar.java中创建主类:package com.examples; import org.apache.spark.sql.SparkSession; import java.util.stream.Collectors; public class SparkJar { public static void main(String[] args) { SparkSession spark = SparkSession.builder().getOrCreate(); // Prints the arguments to the class, which // are job parameters when run as a job: System.out.println(String.join(", ", args)); // Shows using spark: System.out.println(spark.version()); System.out.println( spark.range(10).limit(3).collectAsList().stream() .map(Object::toString) .collect(Collectors.joining(" ")) ); } }若要生成 JAR 文件,请运行以下命令:
mvn clean package编译后的 JAR 会在
target/文件夹中创建,名称为my-spark-app-1.0-SNAPSHOT.jar。
管理依赖项
若要使您的 JAR 能够在无服务器计算上使用某个库,请执行以下操作:
-
使用 提供的库:无服务器计算包括 Databricks Connect 和一组特选的公共库。 如果您的版本兼容,请在构建中将其声明为
provided,并且不要将其包含在 JAR 中。 - 作为环境库附加:如果该库尚未提供,请将其添加到无服务器环境中。 对于不想包含的仅限运行时的库,请使用此功能。
- 连接到外部数据库:对于 JDBC 源,请使用 JDBC 连接 ,而不是包括驱动程序。 JDBC 连接由 Unity 目录管理。 系统会为你处理凭据、世系和治理。
提供的库
以下库是必需的依赖项,在无服务器计算中默认可用。 在生成中声明它们 provided 。 打包这些库的自有版本会在运行时触发 NoSuchMethodError。
注释
下面列出的库版本适用于 无服务器环境版本 4。 有关其他环境版本的已安装库,请参阅 无服务器环境版本说明 参考。
-
com.databricks:databricks-connect_2.13,版本 17.3.2 -
org.scala-lang:scala-library_2.13,版本 2.13.16 -
org.scala-lang:scala-reflect_2.13,版本 2.13.16 -
org.slf4j:slf4j-api,版本 2.0.10 -
org.apache.logging.log4j:log4j-api,版本 2.20.0 -
org.apache.logging.log4j:log4j-core,版本 2.20.0 -
org.apache.httpcomponents:httpclient,版本 4.5.14 -
org.apache.httpcomponents:httpcore,版本 4.4.16 -
com.fasterxml.jackson.core:jackson-databind,版本 2.15.2 -
com.fasterxml.jackson.core:jackson-core,版本 2.15.2 -
com.fasterxml.jackson.core:jackson-annotations,版本 2.15.2 -
com.fasterxml.jackson.datatype:jackson-datatype-jsr310,版本 2.15.2 -
com.google.guava:guava版本 32.0.1-jre -
commons-io:commons-io,版本 2.14.0 -
org.json4s:json4s-jackson_2.13,版本 4.0.7 -
org.apache.commons:commons-lang3,版本 3.14.0 -
org.apache.commons:commons-configuration2,版本 2.11.0 -
org.apache.commons:commons-text版本 1.12.0 -
com.databricks:databricks-sdk-java版本 0.52.0 -
com.databricks:databricks-dbutils-scala_2.13,版本 0.1.4
步骤 2:创建用于运行 JAR 的作业
在工作区中,单击
,然后在边栏中选择作业和管道。
单击创建,然后选择作业。
单击 JAR 磁贴以配置第一个任务。 如果 JAR 磁贴不可用,请单击“ 添加其他任务类型 ”并搜索 JAR。
(可选)将默认名称
New Job <date-time>替换为您选择的作业名称。在 任务名称中,输入任务的名称,例如
JAR_example。如有必要,请从“类型”下拉菜单中选择 JAR。
对于 Main 类,请输入 JAR 的包和类。 如果遵循前面的示例,请输入
com.examples.SparkJar。对于 “计算”,请选择“ 无服务器”。
配置无服务器环境:
- 选择环境,然后单击
编辑 以对其进行配置。
- 为环境版本选择 4 或更高版本。
- 通过将 JAR 文件拖放到文件选择器,或浏览以从 Unity 目录卷或工作区位置选择它来添加 JAR 文件。
- 选择环境,然后单击
对于此示例,请输入 作为“参数”。
["Hello", "World!"]单击“创建任务”。
步骤 3:运行作业并查看作业运行详细信息
单击
以运行工作流。 若要查看运行详细信息,请在“已触发的运行”弹出窗口中单击“查看运行”,或者在作业运行视图中单击运行“开始时间”列中的链接。
运行完成后,输出将显示在“ 输出 ”窗格中,包括传递给任务的参数。
故障排除
下表提供了常见异常的故障排除信息。
| Exception | 原因 | 修复 |
|---|---|---|
NoSuchMethodError
scala.*引用类 |
JAR 针对 Scala 2.12 编译;Serverless 环境运行 Scala 2.13 | 使用 scalaVersion := "2.13.16" 重新编译。 确保每个 Scala 依赖项都使用 _2.13 跨版本后缀。 |
NoClassDefFoundError: scala/... |
Scala 2.12 与 2.13 不匹配 | 使用 scalaVersion := "2.13.16" 重新编译。 确保每个 Scala 依赖项都使用 _2.13 跨版本后缀。 |
UnsupportedClassVersionError (版本高于 61 的类文件) |
使用 JDK 18 或更高版本编译;Serverless 运行环境使用 JDK 17 | 使用 <maven.compiler.release>17</maven.compiler.release> (Maven) 或 --release 17 (sbt / javac) |
NoClassDefFoundError: org/apache/spark/...用于内部包(catalyst、、utilsql/util、sql/internal、api/java或rdd) |
使用了 Spark 内部组件或 RDD API。 这些在 Serverless 环境中不可用。 | 使用公共 Spark API(DataFrame/Dataset/SQL)。 查看 Serverless 的限制。 |
ClassNotFoundException 用于 JDBC 驱动程序类(例如 oracle.jdbc.OracleDriver) |
JDBC 驱动程序不在 classpath 上 | 对外部数据库使用 JDBC 连接 。 |
ClassNotFoundException用于第三方类(例如 kotlin.jvm.internal.*) |
该库不在无服务器类路径上。 | 将其添加到 JAR,或使用 无服务器环境将其作为附加 JAR 提供。 |
UnsatisfiedLinkError 引用 /tmp/ 下的文件 |
JAR 中包含的原生库 | Serverless 环境不支持本地库。 使用纯Java等效项,或在经典计算上运行。 |
NoSuchMethodError 来自第三方库(Apache Commons、Guava、Jackson 等) |
你所包含的版本与 Serverless 提供的版本 冲突。 | 使用提供的版本。 在构建中将其标记为 provided,并且不要将其包含在 JAR 中。 |
后续步骤
- 若要了解有关 JAR 任务的详细信息,请参阅 作业的 JAR 任务。
- 若要详细了解如何创建兼容的 JAR,请参阅 创建Azure Databricks兼容的 JAR。
- 若要详细了解如何创建和运行作业,请参阅 Lakeflow 作业。