重要
Databricks 强烈建议使用声明性自动化捆绑包,而不是按照本页中所述手动生成和部署 JAR。 声明性自动化捆绑包可以轻松地从模板创建项目,该模板具有为无服务器配置的正确 Scala、JDK 和 Databricks Connect 版本,还可以将 JAR 简单部署到 Databricks 工作区。 请参阅 使用声明性自动化捆绑包生成 Scala JAR。
Java存档(JAR)包将Java或 Scala 代码打包到单个文件中。 使用 Spark 代码创建 JAR,并将其作为 JAR 任务部署到 Lakeflow 作业中的 无服务器计算 上。
要求
若要生成 JAR,本地开发环境必须安装以下内容:
依赖项版本
重要
若要在不发生故障的情况下在无服务器计算上运行,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.2org.scala-lang:scala-library_2.13,版本 2.13.16org.scala-lang:scala-reflect_2.13,版本 2.13.16org.slf4j:slf4j-api,版本 2.0.10org.apache.logging.log4j:log4j-api,版本 2.20.0org.apache.logging.log4j:log4j-core,版本 2.20.0org.apache.httpcomponents:httpclient,版本 4.5.14org.apache.httpcomponents:httpcore,版本 4.4.16com.fasterxml.jackson.core:jackson-databind,版本 2.15.2com.fasterxml.jackson.core:jackson-core,版本 2.15.2com.fasterxml.jackson.core:jackson-annotations,版本 2.15.2com.fasterxml.jackson.datatype:jackson-datatype-jsr310,版本 2.15.2com.google.guava:guava版本 32.0.1-jrecommons-io:commons-io,版本 2.14.0org.json4s:json4s-jackson_2.13,版本 4.0.7org.apache.commons:commons-lang3,版本 3.14.0org.apache.commons:commons-configuration2,版本 2.11.0org.apache.commons:commons-text版本 1.12.0com.databricks:databricks-sdk-java版本 0.52.0com.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 作业。