将罐子添加到Spark Job-spark-submit


158

没错,已经讨论了很多。

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

模棱两可和/或省略的细节

含糊不清之后,应为每个选项澄清不清楚和/或省略的细节:

  • ClassPath如何受到影响
    • 司机
    • 执行器(用于正在运行的任务)
    • 一点也不
  • 分隔字符:逗号,冒号,分号
  • 如果提供的文件自动分发
    • 用于任务(针对每个执行者)
    • 用于远程驱动程序(如果以群集模式运行)
  • 接受的URI类型:本地文件,hdfs,http等
  • 如果复制公共位置,则该位置在哪里(hdfs,本地?)

影响的选项:

  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文件。

我知道在哪里可以找到主要的spark文档,尤其是有关如何提交,可用的选项以及JavaDoc的信息。但是,这仍然给我留下了很多空白,尽管它也可以部分解决。

我希望这不是那么复杂,并且有人可以给我一个清晰简洁的答案。

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

为了简单起见,可以安全地假设我可以同时使用3个主要选项添加其他应用程序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

另一个发帖的答案上找到了一篇不错的文章。但是,没有什么新知识。海报确实很好地说明了本地驱动程序(yarn-client)和远程驱动程序(yarn-cluster)之间的区别。要牢记绝对重要。


1
您在哪个群集管理器下运行?独立/ YARN / Mesos?
Yuval Itzchakov '16

任何。我打算以此作为对原始文档的澄清。我主要使用独立集群,单实例,yarn-client,yarn-cluster。其他人可能正在使用Mesos。看来你做了一些很好的原创性研究你的博客这一点。最后,我所做的工作基本上与您相同-使用着色器创建一个Uber jar来简化我的部署过程。
悠悠球

1
我将发布有关我们如何部署Spark Standalone的答案,这可能会清除一些问题。
Yuval Itzchakov

6
我已尽力回答您所有的问题。希望对您
有所

@Yuval Itzchakov,就像Yoyo提到的那样,我也使用阴影罐子来捆绑我的所有依赖项,例如case类和其他可能使用的罐子。我试图了解何时会遇到需要多个罐子的情况。我的意思是,我总是可以将多个jar捆绑到1个uber jar中。为什么我不能继续将捆绑了所有依赖项的阴影罐子生活在一起?
Sheel Pancholi

Answers:


177

类路径:

ClassPath的影响取决于您提供的内容。有两种方法可以在类路径上进行设置:

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

如果希望在主服务器和工作服务器上都执行某个JAR,则必须在两个标志中分别指定它们。

分隔符:

遵循与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选择了一个Leader Worker节点以执行Driver进程。这意味着作业不是直接从“主”节点运行。在这里,Spark 不会设置HTTP服务器。您必须通过可用于所有节点的HDFS / S3 / Other来源手动将JARS提供给所有工作节点。

文件接受的URI

“提交应用程序”中,Spark文档很好地解释了文件的可接受前缀:

使用spark-submit时,应用程序jar以及--jars选项随附的所有jar都会自动传输到集群。Spark使用以下URL方案来允许不同的策略来传播jar:

  • 文件:-绝对路径和文件:/ URI由驱动程序的HTTP文件服务器提供,并且每个执行程序都从驱动程序HTTP服务器提取文件。
  • hdfs:,http:,https:,ftp:-如预期的那样,这些从URI下拉文件和JAR
  • 本地:-以local:/开头的URI应该作为每个工作节点上的本地文件存在。这意味着将不会产生网络IO,并且对于推送到每个工作程序或通过NFS,GlusterFS等共享的大文件/ JAR来说效果很好。

请注意,JAR和文件已复制到执行程序节点上每个SparkContext的工作目录中。

如前所述,将JAR复制到每个Worker节点的工作目录中。那到底在哪里?它通常/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文档中提到了这一点:

指定为标志或属性文件中的任何值都将传递到应用程序,并与通过SparkConf指定的那些值合并。直接在SparkConf上设置的属性具有最高优先级,然后将标志传递给spark-submit或spark-shell,然后是spark-defaults.conf文件中的选项

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

让我们分析每个有问题的选项:

  • --jarsvs SparkContext.addJar:这些是相同的,只有一个是通过spark提交设置的,一个是通过代码设置的。选择一个更适合您的套件。需要注意的重要一件事是,使用这两个选项中的任何一个都不会将JAR添加到驱动程序/执行器类路径中,您需要使用这两个选项extraClassPathconfig 显式添加它们。
  • SparkContext.addJarvs SparkContext.addFile:当您的依赖项需要与代码一起使用时,请使用前者。仅在要将任意文件传递到工作程序节点时使用后者,这不是代码中的运行时依赖项。
  • --conf spark.driver.extraClassPath=...--driver-class-path:这些是别名,与选择哪一个无关紧要
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... 与上面相同,别名。
  • --conf spark.executor.extraClassPath=...:当您具有无法包含在超级JAR中的依赖项时(例如,由于库版本之间存在编译时冲突)并且需要在运行时加载时,请使用此函数。
  • --conf spark.executor.extraLibraryPath=...这作为java.library.pathJVM 的选项传递。需要JVM可见的库路径时,请使用此选项。

为了简单起见,可以安全地假设我可以同时使用3个主要选项添加其他应用程序jar文件:

您可以放心地假设仅针对客户端模式,而不适用于群集模式。正如我之前所说。另外,您给出的示例还有一些多余的参数。例如,将JAR传递给--driver-library-path是没有用的,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

4
伟大而全面的答案。谢谢。你也可以告诉更多的最佳实践与部署超级JAR依赖关系外JAR(在外部文件夹库和上市MANIFEST.MF文件)?
jsosnowski

2
@jsosnowski通常,只有在使用超级JAR解决非常复杂的冲突时,我才选择使用外部jar。通常,我可以简单地通过使用SBT assemblyMergeStrategy并在发生冲突时选择所需的类来解决问题。我通常会建议相同。
Yuval Itzchakov

9
@ yuval-itzchakov感谢您的出色回答,非常有帮助。我想强调的一点是要帮助可能犯过与我相同的错误的其他人。--jars参数仅将jar传输到集群中的每台计算机。它不会告诉spark在类路径搜索中使用它们。也需要--driver-class-path(或类似的参数或配置参数)。我最初以为它们是做同一件事的替代方法。
蒂姆·瑞安

1
@TimRyan一定。如果您看答案的最后一部分,我会将jar传递给--jars标志驱动程序/执行程序类路径。
Yuval Itzchakov

1
最终,我找到了如何将环境变量注入zeppelin-env.sh并添加--jars到中SPARK_SUBMIT_OPTIONS。那行得通。我使用的URI格式为--jars=local:///mnt/dir/file.jar
迈克

4

另一种方法spark 2.1.0--conf spark.driver.userClassPathFirst=true在spark-submit期间使用,该方法通过为用户添加的带有--jars选项的jars赋予优先级,从而更改依赖项加载的优先级,从而更改spark-job的行为。


2
您将必须小心-因为这样做可能会打破火花。这应该是最后的解决方案。尽管我不确定,但潜在地它也可能会干扰在纱线客户端模式下使用的与纱线连接的层。
YoYo

谢谢你的提醒。有什么方法可以仅对1个jar进行优先级排序,该版本确实存在于服务器的较旧版本中,但是您无法物理替换,并且知道自己不想使用它?
斯坦尼斯拉夫

1
我想在这种情况下,您可以按照建议的方式尝试。没说那绝对不是。另外请注意,该选项被标记为“实验性”-请注意警告!没有一种安全的方法可以将库的一个版本优先于另一个版本。在某些实现中,这可以通过将一个库移动到另一个名称空间中来解决,因此您可以同时使用两个版本。
YoYo

1

yarnas部署模式的情况下,其他与jar和classpath有关的可配置Spark选项如下:
从spark文档中,

spark.yarn.jars

包含要分发到YARN容器的Spark代码的库列表。默认情况下,YARN上的Spark将使用本地安装的Spark jar,但是Spark jar也可以位于HDFS上的世界可读位置。这使YARN可以将其缓存在节点上,因此不需要在每次运行应用程序时将其分发。例如,要指向HDFS上的jar,请将此配置设置为hdfs:/// some / path。允许使用小球。

spark.yarn.archive

包含所需Spark jar的归档文件,用于分发到YARN缓存。如果设置,则此配置将替换spark.yarn.jars,并且在所有应用程序容器中使用存档。归档文件应在其根目录中包含jar文件。与上一个选项一样,存档文件也可以托管在HDFS上,以加快文件分发速度。

用户可以配置此参数以指定其jar,然后将其包含在Spark驱动程序的类路径中。


1

当与--master yarn-cluster一起使用spark-submit时,应用程序jar以及--jars选项随附的所有jar都会自动传输到集群。--jars之后提供的URL必须用逗号分隔。该列表包含在驱动程序和执行程序的类路径中

范例:

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

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


0

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

如果指定--driver-class-path并且在纱线簇模式下执行,则不会更新驱动程序类。我们可以在选项卡环境下的spark ui或spark历史记录服务器下验证类路径是否已更新。

对我来说有效的选项是传递包含目录扩展名的jar,并在yarn cluster模式下工作--conf。最好将驱动程序和执行程序类路径传递为--conf,这会将它们添加到spark会话对象本身,并且这些路径会反映在Spark Configuration中。但是请确保将jars放在整个群集的同一路径上。

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

新年快乐!
悠悠球'18

新年快乐YoYo
Tanveer '18

0

当我们使用spark-submit实用工具提交spark作业时,有一个option --jars。使用此选项,我们可以将jar文件传递给spark应用程序。


—jar原始张贴者提到了此选项,并通过一个以上的答案进行了更详细的讨论。看来您没有提供任何新东西?
优悠
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.