通过 REST 提交 EMR Yarn 应用程序

Posted

技术标签:

【中文标题】通过 REST 提交 EMR Yarn 应用程序【英文标题】:EMR Yarn application submission via REST 【发布时间】:2019-02-04 09:28:36 【问题描述】:

我在 AWS 中有一个带有 YARN 的 Hadoop 集群,我向该集群提交了 Spark 应用程序。我通过 REST 请求工作,按照本文档中的说明提交 XML:YARN REST API。它适用于常规集群。

我目前正在做一个 POC 来使用 EMR 集群,而不是通常的 POC,我使用现有的 REST 命令并通过 SSH 与 EMR 的内部 YARN 进行通信,如下所示:Web access of internal EMR services。它适用于大多数 REST 命令,例如 POST http://<rm http address:port>/ws/v1/cluster/apps/new-application,但是当我提交一个新应用程序时它立即失败并报告它找不到 ApplicationMaster。

日志类型:stderr

日志上传时间:2019年2月3日星期日17:18:35 +0000

日志长度:88

错误:无法找到或加载主类 org.apache.spark.deploy.yarn.ApplicationMaster

我怀疑这以某种方式连接到类路径,当我添加到 REST 提交应用程序节点的类路径标志以及所有 jars (/usr/lib/spark/jars/*) 的 EMR FS 位置时,它发现ApplicationMaster 但随后无法在核心实例中找到 Jars,并出现以下奇怪的错误日志:

日志类型:stderr

日志上传时间:2019年1月31日星期四15:11:21 +0000

日志长度:89

错误:无法找到或加载主类 .usr.lib.spark.jars.datanucleus-core-3.2.10.jar

最不寻常的是它试图描述它找不到的 jar 的方式,而不是类。经过进一步调查,我找到了原因:当Java命令发送到Core实例时,它将类路径解析为它的三个文件:java -server -classpath /usr/lib/spark/jars/datanucleus-api-jdo-3.2.6.jar /usr/lib/spark/jars/datanucleus-core-3.2.10.jar /usr/lib/spark/jars/datanucleus-rdbms-3.2.9.jar ...,因此尝试执行“/usr/lib/spark/jars/datanucleus-core -3.2.10.jar" 就好像它是一个可运行的。问题是如果我尝试将类路径更改为更具体,或者如果我尝试删除它,应用程序将再次失败,因为找不到 ApplicationMaster。

我发送给 YARN 的 REST 请求是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<application-submission-context> 
<application-id>application_1549270910165_0001</application-id> 
<application-name> .... some name .....</application-name> 
<queue>default</queue> 
<priority>0</priority> 
<am-container-spec> 
<local-resources> 
    <entry>

 ....... MANY MANY RESOURCES ......

        </value>
    </entry>

</local-resources> 
<environment> 
<entry> 
<key>SPARK_YARN_STAGING_DIR</key> 
<value>..... staging directory in our HDFS ..... </value> 
</entry> 
<entry> 
<key>CLASSPATH</key> 
<value>$PWD:$PWD/__spark_conf__:$PWD/__spark_libs__/*:/usr/lib/spark/jars/*:/usr/lib/spark/yarn/lib/*:%HADOOP_CONF_DIR%:%HAOOP_COMMON_HOME%/share/hadoop/common/*:%HADOOP_COMMON_HOME%/share/hadoop/common/lib/*:%HADOOP_HDFS_HOME%/share/hadoop/hdfs/*:%HADOOP_HDFS_HOME%/share/hadoop/hdfs/lib/*:%HADOOP_YARN_HOME%/share/hadoop/yarn/*:%HADOOP_YARN_HOME%/share/hadoop/yarn/lib/*:%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/*:%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/lib/*:$PWD/__spark_conf__/__hadoop_conf__</value> 
</entry>
<entry>
<key>SPARK_USER</key>
<value>... user name ....</value>
</entry>
</environment>
<commands> 
<command>command=$JAVA_HOME/bin/java -classpath '/usr/lib/spark/jars/*' -server -Xmx5120M -Djava.io.tmpdir=$PWD/tmp '-XX:hashCode=0' '-Dlog4j.configuration=log4j-client.cfg' '-Dhdp.version=2.8.4' -Dspark.yarn.app.container.log.dir=&lt;LOG_DIR&gt; org.apache.spark.deploy.yarn.ApplicationMaster ... some jar and arguments ....  --properties-file $PWD/__spark_conf__/__spark_conf__.properties 1&gt; &lt;LOG_DIR&gt;/stdout 2&gt; &lt;LOG_DIR&gt;/stderr</command> 
</commands> 
</am-container-spec> 
<unmanaged-AM>false</unmanaged-AM> 
<max-app-attempts>1</max-app-attempts> 
<resource> 
<memory>5632</memory> 
<vCores>1</vCores> 
</resource> 
<application-type>SPARK</application-type> 
<keep-containers-across-application-attempts>false</keep-containers-across-application-attempts> 
<application-tags> 
<tag>.... product tag .....</tag> 
</application-tags> 
<log-aggregation-context/> 
<attempt-failures-validity-interval>1</attempt-failures-validity-interval> 
<reservation-id/> 
</application-submission-context>

我会很感激任何线索。

【问题讨论】:

【参考方案1】:

经过长时间的搜索,我发现应用程序无法加载类org.apache.spark.deploy.yarn.ApplicationMaster的原因是因为这不是EMR核心实例使用的ApplicationMaster的版本-它使用org.apache.hadoop.yarn.applications.distributedshell.ApplicationMaster,这需要输入中的CLASSPATH 段包括/usr/lib/hadoop-yarn/*。我更改了 REST 请求的输入 XML 中的两个参数,它成功启动。我仍然需要为 EMR 实施配置正确的 CLASSPATH 以使应用程序成功完成,但这个问题的主要挑战已经解决。

更新:最终我决定在 EMR 中添加一个步骤并使用参数实际上是一种更简单的方法来处理它。我在 Maven 依赖项中添加了 EMR AWS Java SDK:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-emr</artifactId>
    <version>1.11.486</version>
</dependency>

并添加了以下代码:

AddJobFlowStepsResult result = emr.addJobFlowSteps(new AddJobFlowStepsRequest()
            .withJobFlowId(clusterId)
            .withSteps(new StepConfig()
                    .withName(name)
                    .withActionOnFailure(ActionOnFailure.CONTINUE)
                    .withHadoopJarStep(new HadoopJarStepConfig()
                            .withJar("command-runner.jar")
                            .withArgs(stepargs))));

stepargs 取自我的原始 REST 请求,包括要使用的 jar 和文件 - 只需使用 spark-submit:

List<String> stepargs = new ArrayList<String>();
stepargs.add("spark-submit");
stepargs.add("--class");
stepargs.add(mainClass);
stepargs.add("--deploy-mode");
stepargs.add("cluster");
stepargs.add("--master");
stepargs.add("yarn");
stepargs.add("--files");
stepargs.add(files);
stepargs.add("--jars");
stepargs.add(jars);
stepargs.add("--properties-file");
stepargs.add(confFileName);
stepargs.add(jar);
Iterator<String> itr = args.iterator();
while (itr.hasNext()) 
    String arg = itr.next();
    if (arg.equals("--arg")) 
        stepargs.add(itr.next());
    

【讨论】:

以上是关于通过 REST 提交 EMR Yarn 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

我的 spark 代码没有使用 Yarn aws EMR 中可用的所有执行器

Yarn 显示作业已成功,但 EMR 显示该步骤仍在运行

Flink EMR Deployment 无法获取 Yarn 上下文,只能作为本地应用程序执行

Oozie提交作业总结

Oozie提交作业总结

如何设置 Zeppelin 以使用远程 EMR Yarn 集群