将 JAR 文件添加到 Spark 作业 - spark-submit

Add JAR files to a Spark job - spark-submit

没错...已经讨论了很多。

但是,有很多歧义和提供的一些答案......包括在 jars/executor/driver 配置或选项中复制 JAR 引用。

模棱两可and/or省略细节

以下歧义,不明确,and/or省略的细节应针对每个选项进行澄清:

影响的选项:

  1. --jars
  2. SparkContext.addJar(...)方法
  3. SparkContext.addFile(...)方法
  4. --conf spark.driver.extraClassPath=...--driver-class-path ...
  5. --conf spark.driver.extraLibraryPath=...,或--driver-library-path ...
  6. --conf spark.executor.extraClassPath=...
  7. --conf spark.executor.extraLibraryPath=...
  8. 别忘了,spark-submit的最后一个参数也是一个.jar文件。

我知道在哪里可以找到 main Apache Spark documentation, and specifically about how to submit, the options available, and also the JavaDoc。然而,这给我留下了很多漏洞,虽然它也被部分地回答了。

希望不要那么复杂,希望有人能给我一个简洁明了的答案。

如果我从文档中猜测,似乎 --jarsSparkContext addJaraddFile 方法将自动分发文件,而其他选项仅修改 ClassPath。

为简单起见,假设我可以同时使用三个主要选项添加额外的应用程序 JAR 文件是否安全?

spark-submit --jar additional1.jar,additional2.jar \
  --driver-library-path additional1.jar:additional2.jar \
  --conf spark.executor.extraLibraryPath=additional1.jar:additional2.jar \
  --class MyClass main-application.jar

我在 an answer to another posting 上找到了一篇不错的文章。然而,并没有学到任何新东西。张贴者确实对 local driver (yarn-client) 和 remote driver[=88 之间的区别做了很好的评论=] (yarn-cluster)。牢记这一点绝对重要。

类路径:

ClassPath 会受到影响,具体取决于您提供的内容。有几种方法可以在 class 路径上进行设置:

  • spark.driver.extraClassPath 或者它的别名 --driver-class-path 在节点上设置额外的 class 路径 运行 驱动程序。
  • spark.executor.extraClassPath 在 Worker 节点上设置额外的 class 路径。

如果您希望某个 JAR 同时在 Master 和 Worker 上生效,您必须在两个标志中分别指定它们。

分隔符:

Following the same rules as the JVM:

  • Linux:一个冒号,:
    • 例如:--conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar:/opt/prog/aws-java-sdk-1.10.50.jar"
  • Windows:一个分号,;
    • 例如:--conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar;/opt/prog/aws-java-sdk-1.10.50.jar"

文件分发:

这取决于您运行工作的模式:

  1. 客户端模式 - Spark 启动一个 Netty HTTP 服务器,它在启动时为每个工作节点分发文件。您可以在启动 Spark 作业时看到:

    16/05/08 17:29:12 INFO HttpFileServer: HTTP File server directory is /tmp/spark-48911afa-db63-4ffc-a298-015e8b96bc55/httpd-84ae312b-5863-4f4c-a1ea-537bfca2bc2b
    16/05/08 17:29:12 INFO HttpServer: Starting HTTP Server
    16/05/08 17:29:12 INFO Utils: Successfully started service 'HTTP file server' on port 58922.
    16/05/08 17:29:12 INFO SparkContext: Added JAR /opt/foo.jar at http://***:58922/jars/com.mycode.jar with timestamp 1462728552732
    16/05/08 17:29:12 INFO SparkContext: Added JAR /opt/aws-java-sdk-1.10.50.jar at http://***:58922/jars/aws-java-sdk-1.10.50.jar with timestamp 1462728552767
    
  2. 集群模式 - 在集群模式下,Spark 选择了一个领导者 Worker 节点来执行 Driver 进程。这意味着作业不是直接从 Master 节点 运行ning。此处,Spark 不会 设置 HTTP 服务器。您必须通过 HDFS、S3 或所有节点都可用的其他来源手动使您的 JAR 文件可供所有工作节点使用。

接受的文件 URI

"Submitting Applications" 中,Spark 文档很好地解释了可接受的文件前缀:

When using spark-submit, the application jar along with any jars included with the --jars option will be automatically transferred to the cluster. Spark uses the following URL scheme to allow different strategies for disseminating jars:

  • file: - Absolute paths and file:/ URIs are served by the driver’s HTTP file server, and every executor pulls the file from the driver HTTP server.
  • hdfs:, http:, https:, ftp: - these pull down files and JARs from the URI as expected
  • local: - a URI starting with local:/ is expected to exist as a local file on each worker node. This means that no network IO will be incurred, and works well for large files/JARs that are pushed to each worker, or shared via NFS, GlusterFS, etc.

Note that JARs and files are copied to the working directory for each SparkContext on the executor nodes.

如前所述,JAR 文件被复制到每个 Worker 节点的 working directory。那到底在哪里?在/var/run/spark/work下通常是,你会看到它们是这样的:

drwxr-xr-x    3 spark spark   4096 May 15 06:16 app-20160515061614-0027
drwxr-xr-x    3 spark spark   4096 May 15 07:04 app-20160515070442-0028
drwxr-xr-x    3 spark spark   4096 May 15 07:18 app-20160515071819-0029
drwxr-xr-x    3 spark spark   4096 May 15 07:38 app-20160515073852-0030
drwxr-xr-x    3 spark spark   4096 May 15 08:13 app-20160515081350-0031
drwxr-xr-x    3 spark spark   4096 May 18 17:20 app-20160518172020-0032
drwxr-xr-x    3 spark spark   4096 May 18 17:20 app-20160518172045-0033

当您查看内部时,您会看到您部署的所有 JAR 文件:

[*@*]$ cd /var/run/spark/work/app-20160508173423-0014/1/
[*@*]$ ll
total 89988
-rwxr-xr-x 1 spark spark   801117 May  8 17:34 awscala_2.10-0.5.5.jar
-rwxr-xr-x 1 spark spark 29558264 May  8 17:34 aws-java-sdk-1.10.50.jar
-rwxr-xr-x 1 spark spark 59466931 May  8 17:34 com.mycode.code.jar
-rwxr-xr-x 1 spark spark  2308517 May  8 17:34 guava-19.0.jar
-rw-r--r-- 1 spark spark      457 May  8 17:34 stderr
-rw-r--r-- 1 spark spark        0 May  8 17:34 stdout

受影响的选项:

最重要的是要了解优先级。如果您通过代码传递任何 属性,它将优先于您通过 spark-submit 指定的任何选项。 Spark 文档中提到了这一点:

Any values specified as flags or in the properties file will be passed on to the application and merged with those specified through SparkConf. Properties set directly on the SparkConf take highest precedence, then flags passed to spark-submit or spark-shell, then options in the spark-defaults.conf file

因此请确保将这些值设置在正确的位置,这样当一个值优先于另一个值时您就不会感到惊讶。

让我们分析一下问题中的每个选项:

  • --jars vs SparkContext.addJar:它们是相同的。只有一个是通过 Spark 提交设置的,一个是通过代码设置的。选择一个更适合你的。需要注意的一件重要事情是,使用这些选项中的任何一个 都不会将 JAR 文件添加到您的 driver/executor class 路径 。您需要在两者上使用 extraClassPath 配置显式添加它们。
  • SparkContext.addJar vs SparkContext.addFile:当你有一个需要与你的代码一起使用的dependency时,使用前者。当您只是想将任意文件传递到您的工作节点时使用后者,这在您的代码中不是 运行 时间依赖性。
  • --conf spark.driver.extraClassPath=...--driver-class-path:这些是别名,选择哪个都无所谓
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ...同上,别名。
  • --conf spark.executor.extraClassPath=...:当你有一个不能包含在 über JAR 中的依赖项(例如,因为库版本之间存在编译时冲突)并且你需要在 运行时间.
  • --conf spark.executor.extraLibraryPath=... 这作为 JVM 的 java.library.path 选项传递。当您需要 JVM 可见的库路径时使用它。

Would it be safe to assume that for simplicity, I can add additional application jar files using the 3 main options at the same time:

您可以安全地假设这仅适用于 Client 模式,而不适用于 Cluster 模式。正如我之前所说。此外,您给出的示例有一些多余的参数。例如,将 JAR 文件传递​​给 --driver-library-path 是没有用的。如果您希望它们位于您的 class 路径上,则需要将它们传递给 extraClassPath。最终,当您在驱动程序和工作人员上部署外部 JAR 文件时,您需要:

spark-submit --jars additional1.jar,additional2.jar \
  --driver-class-path additional1.jar:additional2.jar \
  --conf spark.executor.extraClassPath=additional1.jar:additional2.jar \
  --class MyClass main-application.jar

Apache Spark 2.1.0 中的另一种方法是在 spark-submit 期间使用 --conf spark.driver.userClassPathFirst=true 更改依赖加载的优先级,从而通过优先考虑 JAR 来更改 spark-job 的行为用户使用 --jars 选项添加到 class 路径的文件。

使用--jars有一个限制:如果你想为jar/xml个文件的位置指定一个目录,它不允许目录扩展。这意味着如果您需要为每个 JAR 文件指定一个绝对路径。

如果您指定 --driver-class-path 并且您在 yarn 集群模式下执行,则驱动程序 class 不会更新。我们可以在tab环境下的SparkUI或者Spark history server下验证class路径是否更新。

让我传递包含目录扩展并在 yarn 集群模式下工作的 JAR 文件的选项是 --conf 选项。最好将驱动程序和执行程序 class 路径作为 --conf 传递,这会将它们添加到 Spark 会话对象本身,并且这些路径会反映在 Spark 配置中。但是确保将 JAR 文件放在集群中的同一路径上。

spark-submit \
  --master yarn \
  --queue spark_queue \
  --deploy-mode cluster    \
  --num-executors 12 \
  --executor-memory 4g \
  --driver-memory 8g \
  --executor-cores 4 \
  --conf spark.ui.enabled=False \
  --conf spark.driver.extraClassPath=/usr/hdp/current/hbase-master/lib/hbase-server.jar:/usr/hdp/current/hbase-master/lib/hbase-common.jar:/usr/hdp/current/hbase-master/lib/hbase-client.jar:/usr/hdp/current/hbase-master/lib/zookeeper.jar:/usr/hdp/current/hbase-master/lib/hbase-protocol.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/scopt_2.11-3.3.0.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/spark-examples_2.10-1.1.0.jar:/etc/hbase/conf \
  --conf spark.hadoop.mapred.output.dir=/tmp \
  --conf spark.executor.extraClassPath=/usr/hdp/current/hbase-master/lib/hbase-server.jar:/usr/hdp/current/hbase-master/lib/hbase-common.jar:/usr/hdp/current/hbase-master/lib/hbase-client.jar:/usr/hdp/current/hbase-master/lib/zookeeper.jar:/usr/hdp/current/hbase-master/lib/hbase-protocol.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/scopt_2.11-3.3.0.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/spark-examples_2.10-1.1.0.jar:/etc/hbase/conf \
  --conf spark.hadoop.mapreduce.output.fileoutputformat.outputdir=/tmp

虽然我们使用 spark-submit 实用程序提交 Apache Spark 作业,但有一个选项 --jars 。使用此选项,我们可以将 JAR 文件传递​​给 Spark 应用程序。

其他与 JAR 文件和类路径相关的可配置 Spark 选项,在 yarn 作为部署模式的情况下如下。

来自 Spark 文档,

spark.yarn.jars

List of libraries containing Spark code to distribute to YARN containers. By default, Spark on YARN will use Spark jars installed locally, but the Spark jars can also be in a world-readable location on HDFS. This allows YARN to cache it on nodes so that it doesn't need to be distributed each time an application runs. To point to jars on HDFS, for example, set this configuration to hdfs:///some/path. Globs are allowed.

spark.yarn.archive

An archive containing needed Spark jars for distribution to the YARN cache. If set, this configuration replaces spark.yarn.jars and the archive is used in all the application's containers. The archive should contain jar files in its root directory. Like with the previous option, the archive can also be hosted on HDFS to speed up file distribution.

用户可以配置此参数来指定他们的 JAR 文件,这些文件又会包含在 Spark 驱动程序的类路径中。

当将 spark-submit 与 --master yarn-cluster 一起使用时,应用程序 JAR 文件以及包含在 --jars 选项中的任何 JAR 文件将自动传输到簇。在 --jars 之后提供的 URL 必须用逗号分隔。该列表包含在驱动程序和执行程序类路径中

示例:

spark-submit --master yarn-cluster --jars ../lib/misc.jar, ../lib/test.jar --class MainClass MainApp.jar

参考

Submitting Applications

我知道使用 --jars 选项添加 jar 也会自动将其添加到类路径中。

https://spark.apache.org/docs/3.2.1/submitting-applications.html

That list is included in the driver and executor classpaths.