【问题标题】:How to access external property file in spark-submit job?如何在 spark-submit 作业中访问外部属性文件?
【发布时间】:2019-12-11 07:21:01
【问题描述】:

我使用的是 spark 2.4.1 版本和 java8。 我正在尝试在使用 spark-submit 提交我的 spark 作业时加载外部属性文件。

因为我使用下面的 TypeSafe 来加载我的属性文件。

 <groupId>com.typesafe</groupId>
    <artifactId>config</artifactId>
    <version>1.3.1</version>

在我使用的代码中

public static Config loadEnvProperties(String environment) {
      Config appConf = ConfigFactory.load();  // loads my "resouces" folder "application.properties" file
      return  appConf.getConfig(environment);
  }

为了将这个“application.properties”文件外部化,我按照专家的建议尝试了这个,而 spark-submit 如下所示

spark-submit \
--master yarn \
--deploy-mode cluster \
--name Extractor  \
--jars "/local/apps/jars/*.jar" \
--files /local/apps/log4j.properties \
--files /local/apps/applicationNew.properties \
--class Driver \
--conf spark.driver.extraJavaOptions=-Dconfig.file=./applicationNew.properties \
--conf spark.executor.extraJavaOptions=-Dconfig.file=./applicationNew.properties \
--conf spark.driver.extraJavaOptions=-Dlog4j.configuration=log4j.properties \
--conf spark.executor.extraJavaOptions=-Dlog4j.configuration=log4j.properties \
--conf spark.driver.extraJavaOptions=-Dlog4j.debug \
--conf spark.driver.extraClassPath=. \
  migration-0.0.1.jar sit 

我将“log4j.properties”和“applicationNew.properties”文件放置在我运行 spark-submit 的同一文件夹中。

1)如果我保留在上面的shell脚本中

--files /local/apps/log4j.properties,  /local/apps/applicationNew.properties \

错误:

Exception in thread "main" org.apache.spark.SparkException: Cannot load main class from JAR file:/local/apps//applicationNew.properties
        at org.apache.spark.deploy.SparkSubmitArguments.error(SparkSubmitArguments.scala:657)

那么这里有什么问题呢?

2) 然后我改变了上面的脚本,如图所示,即

  --files /local/apps/log4j.properties \
    --files /local/apps/applicationNew.properties \

当我运行 spark 作业时,我会收到以下错误。

19/08/02 14:19:09 INFO yarn.ApplicationMaster: Final app status: FAILED, exitCode: 13, (reason: User class threw exception: com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'sit'
        at com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:152)

那么这里有什么问题?为什么不加载 applicationNew.properties 文件?

3) 当我如下调试时 即打印“config.file”

String ss = System.getProperty("config.file");
logger.error ("config.file : {}" , ss); 

错误:

19/08/02 14:19:09 ERROR Driver: config.file : null
19/08/02 14:19:09 ERROR yarn.ApplicationMaster: User class threw exception: com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'sit'

那么如何从 spark-submit 设置“config.file”选项?

如何修复上述错误并从外部 applicationNew.properties 文件加载属性?

【问题讨论】:

  • 试试这个,--driver-java-options -Dconfig.file=./path/conf.file
  • @Lamanus 您使用的是哪个版本的 spark ?我的是 2.4.1 ...不,相同的错误 19/08/02 16:40:12 错误驱动程序:config.file:null 19/08/02 16:40:12 错误 yarn.ApplicationMaster:用户类抛出异常:com .typesafe.config.ConfigException$Missing:没有找到键“坐”的配置设置
  • 2.4.x 有效,但我的只有一个配置文件。 --files 在我的情况下不起作用。
  • @Lamanus 我可以删除其他 --file 来检查它是否有效,executor java 选项呢?
  • 我没有也从未见过那种选项。

标签: apache-spark


【解决方案1】:

列出--files--jars 和其他类似参数的文件的正确方法是通过逗号不带任何空格(这是至关重要的,您会看到有关无效的异常正是因为这个主类):

--files /local/apps/log4j.properties,/local/apps/applicationNew.properties

如果文件名本身包含空格,则应使用引号将这些空格转义:

--files "/some/path with/spaces.properties,/another path with/spaces.properties"

另一个问题是您两次指定相同的属性:

...
--conf spark.driver.extraJavaOptions=-Dconfig.file=./applicationNew.properties \
...
--conf spark.driver.extraJavaOptions=-Dlog4j.configuration=log4j.properties \
...

spark-submit 无法知道如何合并这些值,因此只使用其中一个。这就是您看到 config.file 系统属性的 null 的原因:它只是第二个 --conf 参数优先并使用 log4j 配置文件的单个路径覆盖 extraJavaOptions 属性。因此,正确的方法是将所有这些值指定为一个属性:

--conf spark.driver.extraJavaOptions="-Dlog4j.configuration=file:./log4j.properties -Dconfig.file=./applicationNew.properties"

请注意,由于引号,整个spark.driver.extraJavaOptions="..." 是一个命令行参数而不是多个命令行参数,这对于 spark-submit 将这些参数正确传递给驱动程序/执行程序 JVM 非常重要。

(我还更改了 log4j.properties 文件以使用正确的 URI 而不是文件。我记得如果没有此路径是 URI,它可能无法正常工作,但您可以尝试任何一种方式并确定。)

【讨论】:

【解决方案2】:

--files 和 SparkFiles.get

使用--files,您应该使用SparkFiles.get 访问资源,如下所示:

$ ./bin/spark-shell --files README.md

scala> import org.apache.spark._
import org.apache.spark._

scala> SparkFiles.get("README.md")
res0: String = /private/var/folders/0w/kb0d3rqn4zb9fcc91pxhgn8w0000gn/T/spark-f0b16df1-fba6-4462-b956-fc14ee6c675a/userFiles-eef6d900-cd79-4364-a4a2-dd177b4841d2/README.md

换句话说,Spark 会将--files 分发给执行程序,但知道文件路径的唯一方法是使用SparkFiles 实用程序。

getResourceAsStream(resourceFile) 和 InputStream

另一种选择是将所有资源文件打包成一个 jar 文件并将其与其他 jar 文件捆绑在一起(作为单个 uber-jar 或仅作为 Spark 应用程序的 CLASSPATH 的一部分)并使用 @987654321 @:

this.getClass.getClassLoader.getResourceAsStream(resourceFile)

这样,无论resourceFile 在哪个jar 文件中,只要它在CLASSPATH 上,它就应该可供应用程序使用。

我很确定任何使用资源文件进行配置的体面的框架或库,例如Typesafe Config,接受InputStream作为读取资源文件的方式。


您还可以将--files 作为 jar 文件的一部分包含在执行程序的 CLASSPATH 的一部分中,但这显然不太灵活(因为每次您想使用不同的文件,你必须重新创建 jar)。

【讨论】:

  • 谢谢,但每次我将文件放入 jar 中,如何将属性文件外部化?
  • Spark 应用程序的每个文件都由spark-submit 自动分发(这是 Spark 的功能之一),因此您不必担心。那么问题是如何访问代码中的文件(内部或外部 jar 文件),该代码期望它位于给定位置的文件系统上。这就是SparkFiles.get 所做的。
  • 我不认为SparkFiles.get 是唯一的方法。从我在各种环境中运行作业时看到的情况来看,如果通过--files 选项分发文件,则它在正在运行的作业的当前工作目录中可用,因此相对路径可以正常工作。
  • @Shyam “每次我将文件放入 jar 中,它会如何将属性文件外部化?” 直到现在我才明白你的问题。 Spark 不会重新打包您的 jar 文件。它们按原样提供,但您的问题是如何访问资源文件,一种方法是使用 SparkFiles.get 或...查看我的更新答案:)
猜你喜欢
  • 2017-03-24
  • 2016-09-05
  • 2019-01-09
  • 2018-08-12
  • 2019-12-08
  • 2017-06-25
  • 2022-01-15
  • 2014-10-03
  • 1970-01-01
相关资源
最近更新 更多