将jar添加到Spark作业 - spark-submit

YoY*_*oYo 139 java scala jar apache-spark spark-submit

真的...已经讨论了很多.

然而,有很多歧义和一些答案提供...包括在jar/executor /驱动程序配置或选项中复制jar引用.

模糊和/或省略的细节

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

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

它影响的选项:

  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 addJar,addFile方法是自动分发文件的方法,而其他选项只是修改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
Run Code Online (Sandbox Code Playgroud)

找到一篇关于一篇文章答案的好文章.然而没有什么新学到的 海报确实很好地评论了本地驱动程序(纱线客户端)和远程驱动程序(纱线群集)之间的区别.记住这一点非常重要.

Yuv*_*kov 154

类路径.

ClassPath会受到影响,具体取决于您提供的内容.有几种方法可以在类路径上设置一些东西:

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

如果您希望某个JAR在Master和Worker上都有效,则必须在BOTH标志中单独指定它们.

分离特征:

遵循与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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 群集模式 - 在群集模式中,spark选择了一个领导者工作节点来执行驱动程序进程.这意味着作业不是直接从主节点运行.在这里,Spark 不会设置HTTP服务器.您必须通过HDFS/S3 /所有节点可用的其他源手动使JARS可用于所有工作节点.

文件的接受URI

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

使用spark-submit时,应用程序jar以及--jars选项中包含的任何jar都将自动传输到群集.Spark使用以下URL方案来允许传播jar的不同策略:

  • file: - 绝对路径和文件:/ URI由驱动程序的HTTP文件服务器提供,每个执行程序从驱动程序HTTP服务器提取文件.
  • hdfs:,http:,https:,ftp: - 这些从URI中按预期下拉文件和JAR
  • local: - 以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
Run Code Online (Sandbox Code Playgroud)

当你向内看时,你会看到你所部署的所有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
Run Code Online (Sandbox Code Playgroud)

受影响的选项:

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

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

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

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

  • --jarsvs SparkContext.addJar:这些是相同的,只有一个是通过spark submit设置的,另一个是通过代码设置的.选择最适合你的那个.需要注意的重要一点是,使用这些选项不加JAR到您的驱动器/执行器的类路径,则需要使用显式添加他们extraClassPath两个配置.
  • SparkContext.addJarvs SparkContext.addFile:当您具有需要与代码一起使用的依赖项时,请使用前者.当您只想将任意文件传递给工作节点时使用后者,这不是代码中的运行时依赖性.
  • --conf spark.driver.extraClassPath=...--driver-class-path:这些是别名,无论您选择哪一个都无关紧要
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... 与上面相同,别名.
  • --conf spark.executor.extraClassPath=...:如果您具有无法包含在uber JAR中的依赖项(例如,因为库版本之间存在编译时冲突)以及您需要在运行时加载的依赖项,请使用此选项.
  • --conf spark.executor.extraLibraryPath=...这是作为java.library.pathJVM 的选项传递的.当您需要JVM可见的库路径时,请使用此选项.

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

您可以安全地假设这只适用于客户端模式,而不是群集模式.正如我之前所说的那样.此外,您给出的示例有一些冗余的参数.例如,传递JAR --driver-library-path是无用的,extraClassPath如果您希望它们位于类路径上,则需要将它们传递给它们.最终,当您在驱动程序和worker上部署外部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
Run Code Online (Sandbox Code Playgroud)

  • @ yuval-itzchakov感谢您的回答,非常有帮助.有一点我想强调帮助那些可能犯过同样错误的人.--jars参数仅将jar传输到集群中的每台机器.它不会告诉spark在类路径搜索中使用它们.还需要--driver-class-path(或类似的参数或配置参数).我最初认为他们是做同样事情的替代方式. (8认同)
  • 伟大而全面的答案.谢谢.您是否还可以通过*uber JAR*与JAR*之外的*依赖关系(外部文件夹中的库并在`MANIFEST.MF`文件中列出)更多地介绍部署中的最佳实践? (3认同)
  • @jsosnowski 通常,当我的 uber JAR 出现非常复杂的冲突时,我只会推迟使用外部 jar。我通常通过使用 SBT 的`assemblyMergeStrategy` 并在发生冲突时选择我需要的类来解决。我通常会推荐相同的。 (2认同)
  • @TimRyan 当然。如果您查看答案的最后部分,我会将 jar 传递给“--jars”标志*和*驱动程序/执行程序类路径。 (2认同)

Sta*_*lav 6

另一种方法spark 2.1.0--conf spark.driver.userClassPathFirst=true在 spark-submit 期间使用它改变依赖加载的优先级,从而改变 spark-job 的行为,通过优先考虑用户添加到类路径的 jars--jars选项。

  • 你必须小心——因为这样做可能会破坏火花。这应该是最后的选择解决方案。在纱线客户端模式下使用时,它可能也会干扰与纱线接口的层,尽管我不确定。 (2认同)