spark-submit 到 Amazon EMR 时如何指定自定义 log4j.configuration 的位置?

How to specify the location of custom log4j.configuration when spark-submit to Amazon EMR?

我正在尝试 运行 EMR 集群中的 spark 作业。

我的 spark-submit 我已经添加了配置以从 log4j.properties

中读取
--files log4j.properties --conf "spark.executor.extraJavaOptions=-Dlog4j.configuration=file:/log4j.properties"

我也添加了

log4j.rootLogger=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=/log/test.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5p %c{7} - %m%n

在我的 log4j 配置中。

无论如何,我在控制台中看到了日志,尽管我没有看到生成的日志文件。我在这里做错了什么?

引用 spark-submit --help:

--files FILES Comma-separated list of files to be placed in the working directory of each executor. File paths of these files in executors can be accessed via SparkFiles.get(fileName).

如果您不能使用 SparkFiles.get(fileName)(对于 log4j 则不能),那么如何处理 FILES 并没有太多说明。

引用 SparkFiles.getscaladoc:

Get the absolute path of a file added through SparkContext.addFile().

那也不会给你太多,但是建议看看source code of SparkFiles.get:

def get(filename: String): String =
  new File(getRootDirectory(), filename).getAbsolutePath()

它的好处是 getRootDirectory() uses an optional property or just the current working directory:

def getRootDirectory(): String =
  SparkEnv.get.driverTmpDir.getOrElse(".")

这提供了一些工作,不是吗?

在驱动程序上,所谓的 driverTmpDir 目录应该很容易在 Web UI 的环境选项卡中找到(在 spark.files 属性 或类路径的 Spark 属性下在源列中标记为 "Added By User" 的条目)。

在执行器上,我会假设一个本地目录,所以我不会使用file:/log4j.properties,而是使用

-Dlog4j.configuration=file://./log4j.properties

-Dlog4j.configuration=file:log4j.properties

注意指定本地工作目录的点(在第一个选项中)或无前导 /(在后者中)。

如果您还没有考虑过,请不要忘记 spark.driver.extraJavaOptions 为驱动程序设置 Java 选项。到目前为止,您一直只关注执行者。

您可能想要将 -Dlog4j.debug=true 添加到 spark.executor.extraJavaOptions 中,它应该打印 log4j 用于查找 log4j.properties.

的位置

我自己还没有在 EMR 或 YARN 集群上检查过这个答案,但相信这可能会给你一些提示,告诉你在哪里可以找到答案。 双手合十!

这是我用来 运行 我在 EMR 中的 uber-jar 的完整命令,我看到在驱动程序和执行程序节点中生成的日志文件。

spark-submit --class com.myapp.cloud.app.UPApp --master yarn --deploy-mode client --driver-memory 4g --executor-memory 2g --executor-cores 8 --文件 log4j.properties --conf "spark.executor.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties" --conf "spark.driver.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties -Dlog4j.debug=true" --conf "spark.executor.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties" --conf "spark.eventLog.dir=/mnt/var/log/" uber-up-0.0.1.jar

其中 log4j.properties 在我的本地文件系统中。

使用 Spark 2.2.0 独立集群,执行器 JVM 首先启动,然后 Spark 分发应用程序 jar 和 --files 这意味着通过

spark.executor.extraJavaOptions=-Dlog4j.configuration=file:log4j-spark.xml

没有意义,因为该文件在执行程序 JVM 启动和 log4j 初始化时尚不存在(未下载)

如果你通过了

spark.executor.extraJavaOptions=-Dlog4j.debug -Dlog4j.configuration=file:log4j-spark.xml

您会在执行程序的 stderr 开始时发现加载 log4j 配置文件失败的尝试

log4j:ERROR Could not parse url [file:log4j-spark.xml].
java.io.FileNotFoundException: log4j-spark.xml (No such file or directory)
...
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties

稍后记录从驱动程序下载 --files

18/07/18 17:24:12 INFO Utils: Fetching spark://123.123.123.123:35171/files/log4j-spark.xml to /ca/tmp-spark/spark-49815375-3f02-456a-94cd-8099a0add073/executor-7df1c819-ffb7-4ef9-b473-4a2f7747237a/spark-0b50a7b9-ca68-4abc-a05f-59df471f2d16/fetchFileTemp5898748096473125894.tmp
18/07/18 17:24:12 INFO Utils: Copying /ca/tmp-spark/spark-49815375-3f02-456a-94cd-8099a0add073/executor-7df1c819-ffb7-4ef9-b473-4a2f7747237a/spark-0b50a7b9-ca68-4abc-a05f-59df471f2d16/-18631083971531927447443_cache to /opt/spark-2.2.0-bin-hadoop2.7/work/app-20180718172407-0225/2/./log4j-spark.xml

它可能与 yarn 或其他集群管理器的工作方式不同,但对于独立集群,您似乎无法在 spark-submit 上为执行程序指定自己的日志记录配置。

您可以在您的作业代码中动态重新配置 log4j (override log4j configuration programmatically: file location for FileAppender),但您需要在执行程序的 JVM 中执行的某些 mapPartition lambda 中仔细执行此操作。或者,也许您可​​以将工作的第一阶段投入其中。尽管一切都很糟糕...