Spark 应用通常依赖于第三方 Java 或 Scala 库。以下是在向 Managed Service for Apache Spark 集群提交 Spark 作业时添加这些依赖项的建议方法:
从本地机器使用
gcloud dataproc jobs submit命令提交作业时,请使用--properties spark.jars.packages=[DEPENDENCIES]标志。
示例:gcloud dataproc jobs submit spark \ --cluster=my-cluster \ --region=region \ --properties=spark.jars.packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
直接在集群上提交作业时, 请使用带有
--packages=[DEPENDENCIES]参数的spark-submit命令。
示例:spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
添加自定义 JAR 文件或软件包时:
避免依赖项冲突
如果 Spark 应用依赖项与 Hadoop 的依赖项冲突,则上述方法可能会失败。导致这种冲突的原因如下:由于 Hadoop 将其
依赖项注入应用的
类路径,因此其依赖项的优先级高于应用的
依赖项。发生冲突时,可能会生成 NoSuchMethodError 或其他错误。
示例:
Guava
是 Google 的 Java 核心库,可供多种库和
框架(包括 Hadoop)使用。如果作业或其依赖项需要使用的 Guava 版本比 Hadoop 使用的版本更高,则可能出现依赖项冲突。
Hadoop v3.0 解决了
这个问题,但依赖早期 Hadoop 版本的应用需要通过以下两个环节的解决方法来避免可能的依赖项冲突。
- 创建一个单独的 JAR,其中包含应用的软件包及其所有依赖项。
- 重新定位超级 JAR 中冲突的依赖项软件包,以防止其路径名与 Hadoop 的依赖项软件包冲突。 可在打包过程中使用插件(请参阅下文)自动执行此重定位(也称为“添加阴影”),而无需修改您的代码。
用 Maven 创建一个超级阴影 JAR
Maven 是构建 Java 应用程序的包管理工具。Maven scala 插件可用于构建用 Scala(即 Spark 应用使用的语言)编写的应用。The Maven shade
插件可用于创建阴影 JAR。
以下是 pom.xml 配置文件示例,用于为位于 com.google.common 软件包中的 Guava 库添加阴影。此配置
指示 Maven 将 com.google.common 软件包重命名为
repackaged.com.google.common,并更新
原始软件包中对类的所有引用。
<?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> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <groupId><!-- YOUR_GROUP_ID --></groupId> <artifactId><!-- YOUR_ARTIFACT_ID --></artifactId> <version><!-- YOUR_PACKAGE_VERSION --></version> <dependencies> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version><!-- YOUR_SPARK_VERSION --></version> <scope>provided</scope> </dependency> <!-- YOUR_DEPENDENCIES --> </dependencies> <build> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <configuration> <scalaVersion><!-- YOUR_SCALA_VERSION --></scalaVersion> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass><!-- YOUR_APPLICATION_MAIN_CLASS --></mainClass> </transformer> <!-- This is needed if you have dependencies that use Service Loader. Most Google Cloud client libraries do. --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/maven/**</exclude> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <relocations> <relocation> <pattern>com</pattern> <shadedPattern>repackaged.com.google.common</shadedPattern> <includes> <include>com.google.common.**</include> </includes> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
要运行该构建,请执行以下操作:
mvn package
关于 pom.xml 的备注:
- ManifestResourceTransformer
会处理 Uber JAR 清单文件 (
MANIFEST.MF) 中的属性。此 清单还可以指定应用的入口点。 - Spark 的 范围
是
provided,因为 Spark 安装在 Managed Service for Apache Spark 上。 - 指定安装在 Managed Service for Apache Spark 集群上的 Spark 版本(请参阅 Managed Service for Apache Spark 版本列表 )。如果您的应用需要的 Spark 版本与 Managed Service for Apache Spark 集群中安装的 版本不同,您可以 编写初始化 操作, 或构建一个自定义映像, 安装应用使用的 Spark 版本。
<filters>条目会从依赖项的META-INF目录中排除签名文件。如果没有此条目,则可能会发生java.lang.SecurityException: Invalid signature file digest for Manifest main attributes运行时 异常,因为签名文件在超级 JAR 环境中无效。- 您可能需要为多个库添加阴影。为此,请添加多个路径。
以下示例演示了如何为 Guava 和 Protobuf 库添加阴影。
<relocation> <pattern>com</pattern> <shadedPattern>repackaged.com</shadedPattern> <includes> <include>com.google.protobuf.**</include> <include>com.google.common.**</include> </includes> </relocation>
用 SBT 创建一个超级阴影 JAR
SBT
是构建 Scala 应用的工具。如需使用 SBT 创建阴影 JAR,请首先向构建定义中添加
sbt-assembly
插件,然后在 project/ 目录下创建名为 assembly.sbt 的文件:
├── src/
└── build.sbt
└── project/
└── assembly.sbt
然后在 assembly.sbt 中添加以下行:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")以下是 build.sbt 配置文件示例,用于为位于 com.google.common package 软件包中的 Guava 库添加阴影。
lazy val commonSettings = Seq( organization := "YOUR_GROUP_ID", name := "YOUR_ARTIFACT_ID", version := "YOUR_PACKAGE_VERSION", scalaVersion := "YOUR_SCALA_VERSION", ) lazy val shaded = (project in file(".")) .settings(commonSettings) mainClass in (Compile, packageBin) := Some("YOUR_APPLICATION_MAIN_CLASS") libraryDependencies ++= Seq( "org.apache.spark" % "spark-sql_2.11" % "YOUR_SPARK_VERSION" % "provided", // YOUR_DEPENDENCIES ) assemblyShadeRules in assembly := Seq( ShadeRule.rename("com.google.common.**" -> "repackaged.com.google.common.@1").inAll )
要运行该构建,请执行以下操作:
sbt assembly
关于 build.sbt 的备注:
- 上述示例中的阴影规则可能无法解决所有依赖项冲突,因为 SBT 使用严格的冲突解决策略。因此,您可能需要提供更精细的规则,这些规则使用
MergeStrategy.first、last、concat、filterDistinctLines、rename或discard策略明确合并特定类型的冲突文件。如需了解详情,请参阅sbt-assembly's 合并 策略 。 - 您可能需要为多个库添加阴影。为此,请添加多个路径。
以下示例演示了如何为 Guava 和 Protobuf 库添加阴影。
assemblyShadeRules in assembly := Seq( ShadeRule.rename("com.google.common.**" -> "repackaged.com.google.common.@1").inAll, ShadeRule.rename("com.google.protobuf.**" -> "repackaged.com.google.protobuf.@1").inAll )
向 Managed Service for Apache Spark 提交超级 JAR
在创建包含 Spark 应用
及其依赖项的超级阴影 JAR 之后,将 JAR 上传到 Cloud Storage,然后向 Managed Service for Apache Spark 提交作业
(使用--jars 标志在
Google Cloud CLI CLI 中,控制台中的Jar 文件 字段, Google Cloud API jarFileUris 字段,或将阴影 JAR 指定为主要
应用 JAR)。
后续步骤
- 请参阅 Spark 示例应用 spark-translate, 其中包含了 Maven 和 SBT 的配置文件。
- 在 Managed Service for Apache Spark 上编写并运行 Spark Scala 作业。请按照快速入门中的说明了解如何在 Managed Service for Apache Spark 集群上编写并运行 Spark Scala 作业。