通过 REST 提交 EMR Yarn 应用程序
EMR Yarn application submission via REST
我在 AWS 中有一个带有 YARN 的 Hadoop 集群,我向其提交了 spark 应用程序。我通过 REST 请求工作,按照本文档中的规定提交 XML:YARN REST API。它适用于常规集群。
我目前正在做一个 POC 来使用 EMR 集群而不是通常的集群,在那里我使用现有的 REST 命令并通过 SSH 简单地与 EMR 的内部 YARN 通信,如此处指定:Web access of internal EMR services.它适用于大多数 REST 命令,例如 POST http://<rm http address:port>/ws/v1/cluster/apps/new-application
,但是当我提交新应用程序时它立即失败并报告找不到 ApplicationMaster。
Log Type: stderr
Log Upload Time: Sun Feb 03 17:18:35 +0000 2019
Log Length: 88
Error: Could not find or load main class org.apache.spark.deploy.yarn.ApplicationMaster
我怀疑它以某种方式连接到 classpath,当我将 classpath 标志添加到 REST 提交应用程序节点时,该标志带有所有 jar 的 EMR FS 位置(/usr/lib/spark/jars/*),它找到了 ApplicationMaster,但随后在核心实例中找不到 Jars,出现了这个奇怪的错误日志:
Log Type: stderr
Log Upload Time: Thu Jan 31 15:11:21 +0000 2019
Log Length: 89
Error: Could not find or load main class .usr.lib.spark.jars.datanucleus-core-3.2.10.jar
最不寻常的是它试图描述它找不到的 jar 的方式,而不是 class。经过进一步调查,我找到了原因:当 Java 命令被发送到 Core 实例时,它将 class 路径解析为其三个文件: 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" 好像它是可运行的。问题是,如果我尝试将 class 路径更改得更具体,或者如果我尝试删除它,应用程序将再次失败,因为找不到 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=<LOG_DIR> org.apache.spark.deploy.yarn.ApplicationMaster ... some jar and arguments .... --properties-file $PWD/__spark_conf__/__spark_conf__.properties 1> <LOG_DIR>/stdout 2> <LOG_DIR>/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>
如果有任何线索,我将不胜感激。
经过长时间的搜索,我发现应用程序无法加载 class 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());
}
}
我在 AWS 中有一个带有 YARN 的 Hadoop 集群,我向其提交了 spark 应用程序。我通过 REST 请求工作,按照本文档中的规定提交 XML:YARN REST API。它适用于常规集群。
我目前正在做一个 POC 来使用 EMR 集群而不是通常的集群,在那里我使用现有的 REST 命令并通过 SSH 简单地与 EMR 的内部 YARN 通信,如此处指定:Web access of internal EMR services.它适用于大多数 REST 命令,例如 POST http://<rm http address:port>/ws/v1/cluster/apps/new-application
,但是当我提交新应用程序时它立即失败并报告找不到 ApplicationMaster。
Log Type: stderr
Log Upload Time: Sun Feb 03 17:18:35 +0000 2019
Log Length: 88
Error: Could not find or load main class org.apache.spark.deploy.yarn.ApplicationMaster
我怀疑它以某种方式连接到 classpath,当我将 classpath 标志添加到 REST 提交应用程序节点时,该标志带有所有 jar 的 EMR FS 位置(/usr/lib/spark/jars/*),它找到了 ApplicationMaster,但随后在核心实例中找不到 Jars,出现了这个奇怪的错误日志:
Log Type: stderr
Log Upload Time: Thu Jan 31 15:11:21 +0000 2019
Log Length: 89
Error: Could not find or load main class .usr.lib.spark.jars.datanucleus-core-3.2.10.jar
最不寻常的是它试图描述它找不到的 jar 的方式,而不是 class。经过进一步调查,我找到了原因:当 Java 命令被发送到 Core 实例时,它将 class 路径解析为其三个文件: 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" 好像它是可运行的。问题是,如果我尝试将 class 路径更改得更具体,或者如果我尝试删除它,应用程序将再次失败,因为找不到 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=<LOG_DIR> org.apache.spark.deploy.yarn.ApplicationMaster ... some jar and arguments .... --properties-file $PWD/__spark_conf__/__spark_conf__.properties 1> <LOG_DIR>/stdout 2> <LOG_DIR>/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>
如果有任何线索,我将不胜感激。
经过长时间的搜索,我发现应用程序无法加载 class 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());
}
}