AWS EMR Spark Cluster - 使用Scala fat JAR的步骤,找不到MainClass

时间:2017-11-22 01:29:34

标签: scala jar executable-jar amazon-emr spark-submit

我有一个用Scala编写的胖罐,由sbt打包。我需要在AWS EMR中的Spark集群中使用它。

如果我手动启动集群,将jar复制到master并使用像这样的命令运行spark-submit作业,它的功能正常...

spark-submit --class org.company.platform.package.SparkSubmit --name platform ./platform-assembly-0.1.0.jar arg0 arg1 arg2

但是......如果我尝试将其添加为EMR集群的一个步骤,它就会失败。 stderr的日志看起来像这样......

Exception in thread "main" java.lang.ClassNotFoundException: package.SparkSubmit
  at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
  at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
  at java.lang.Class.forName0(Native Method)
  at java.lang.Class.forName(Class.java:278)
  at org.apache.hadoop.util.RunJar.run(RunJar.java:214)
  at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

我的build.sbt中的相关设置如下所示......

lazy val root = (project in file(".")).
  settings(
    name := "platform",
    version := "0.1.0",
    scalaVersion := "2.10.5",
    organization := "org.company",
    mainClass in Compile := Some("package/SparkSubmit")
  )

我的MainClass的相应文件看起来像......

package org.company.platform.package

object SparkSubmit {
  def main(args: Array[String]): Unit = {
    // do stuff
  }
}

在EMR控制台中...在“添加步骤”对话框中...在“参数”框旁边,它显示...

“这些传递给JAR中的main函数。如果JAR没有在其清单文件中指定主类,则可以指定另一个类名作为第一个参数。”

我认为因为我在build.sbt中指定了一个主类,我会没事的......但是它失败了并且没有记录关于失败的任何内容。如果我尝试将主类指定为第一个arg,它会记录我在上面发布的失败。

我认为这可能是格式化问题,但我无法理清如何修复它,也没有任何例子出现。我已经尝试在“添加步骤”对话框中提交以下作为args ...

arg0 arg1 arg2
package.SparkSubmit arg0 arg1 arg2
package/SparkSubmit arg0 arg1 arg2
org.company.platform.package.SparkSubmit arg0 arg1 arg2

其他一些人,但没有任何作用。

版本信息... EMR 4.3 Spark 1.6 斯卡拉2.10 sbt 0.13.9

任何想法,我正在制造的那些愚蠢的错误是不是让EMR / Spark找到我的主要课程?

感谢。

1 个答案:

答案 0 :(得分:2)

编辑 - 得到这个"工作"通过制造问题1-6消失,然后集群只是坐在那里说它是"运行"第一步,但它从未完成。我错误地将步骤类型设置为"自定义jar"而不是"火花应用"。切换后,我认为只有问题1"是相关的,仅此一点可能解决了我的问题。我不得不将修复程序退回到下面的问题2,3和5,以使其与#34; spark application"步骤,我怀疑我也可以退出其余部分。 结束编辑

我花了很长时间才开始工作。我会按顺序发布错误和修正,以防其他人在路上行事。

问题1

无论我作为第一个arg尝试并指向MainClass传入的内容......我都得到了同样的错误。问题出在我的build.sbt中。我(错误地)认为root中的组织和名称足以提供包前缀。

我在build.sbt中更改了mainClass,以匹配我在文件顶部声明的包与我的SparkSubmit对象...

mainClass in Compile := Some("org.company.platform.package.SparkSubmit")

然后在"添加步骤"对话框,我刚刚传入args,没有类别指定......所以只是" arg0 arg1 arg2"。

有趣的参考,如果你想在清单和运行中设置不同的MainClass ... How to set main class in build?

问题2

Exception in thread "main" org.apache.spark.SparkException: A master URL must be set in your configuration

我找到了这个参考资料...... https://spark.apache.org/docs/latest/submitting-applications.html#master-urls

我不知道使用哪一个,但由于EMR使用Yarn,我将其设置为" yarn"。 这是错误的。(将其留作生成的后续错误的记录)在SparkSubmit.main()中,我设置了这样的主URL ......

val conf = 
  new SparkConf()
  .setMaster("yarn")
  .setAppName("platform")

问题3

主网址错误消失了,现在这是我的错误......

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/spark/SparkConf

在我的build.sbt中......我将spark-core和spark-sql列为"提供"在libraryDependencies ...我不知道为什么这不作为EMR步骤工作,因为群集已加载Spark ...但我删除了它并将其更改为...

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-core" % "1.6.0", // % "provided",
  "org.apache.spark" %% "spark-sql" % "1.6.0", //  % "provided",
  ...
)

注意 - 删除"提供"我收到了一个新的错误,但是将spark-core和spark-sql的版本更改为1.6.0以匹配EMR 4.3使得它消失了。

问题解决了...创建了新的一个!

问题4

Exception in thread "main" com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'akka.version'

答案就在这里...... https://doc.akka.io/docs/akka/snapshot/general/configuration.html#when-using-jarjar-onejar-assembly-or-any-jar-bundler

基本上,Akka的reference.conf迷路了。我的build.sbt mergeStrategy看起来像这样......

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
   {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case _ => MergeStrategy.first
   }
}

我修改它看起来像这样......

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
   {
    case "reference.conf" => MergeStrategy.concat
    case "application.conf" => MergeStrategy.concat
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case _ => MergeStrategy.first
   }
}

问题5

我猜&#34;纱线&#34;问题2中没有正确的选择。我收到了这个错误......

Exception in thread "main" org.apache.spark.SparkException: Could not parse Master URL: 'yarn'

我将网址更改为&#34; local [2]&#34; ...

val conf = 
  new SparkConf()
  .setMaster("local[2]")
  .setAppName("starling_for_mongo")

这个价值没有正当理由......不确定我实际需要多少线程......或者甚至应用的地方......是在主人中,还是在某个地方的某个地方......我是...我不确定。需要更多地了解这一点,但我只是复制了这里的内容,因为......呃...为什么不呢? https://spark.apache.org/docs/1.6.1/configuration.html#spark-properties

需要了解此处设置的内容。

问题6

接下来出现了很多序列化错误。我不明白为什么,当所有这些代码运行时没有任何问题,如手动spark-submit或spark-shell。我通过基本上修复它,并使每个类扩展Serializable。

结束

这是我的旅程,获取一个用scala编写的工作jar,并使用sbt编译,以充当EMR spark集群中的一个步骤。我希望这可以帮助其他人。