【问题标题】:Spark-submit ClassNotFound exceptionSpark-提交 ClassNotFoundexception
【发布时间】:2014-10-30 13:16:28
【问题描述】:

我在使用这个简单示例时遇到了“ClassNotFound”异常问题:

import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf

import java.net.URLClassLoader

import scala.util.Marshal

class ClassToRoundTrip(val id: Int) extends scala.Serializable {
}

object RoundTripTester {

  def test(id : Int) : ClassToRoundTrip = {

    // Get the current classpath and output. Can we see simpleapp jar?
    val cl = ClassLoader.getSystemClassLoader
    val urls = cl.asInstanceOf[URLClassLoader].getURLs
    urls.foreach(url => println("Executor classpath is:" + url.getFile))

    // Simply instantiating an instance of object and using it works fine.
    val testObj = new ClassToRoundTrip(id)
    println("testObj.id: " + testObj.id)

    val testObjBytes = Marshal.dump(testObj)
    val testObjRoundTrip = Marshal.load[ClassToRoundTrip](testObjBytes)  // <<-- ClassNotFoundException here
    testObjRoundTrip
  }
}

object SimpleApp {
  def main(args: Array[String]) {

    val conf = new SparkConf().setAppName("Simple Application")
    val sc = new SparkContext(conf)

    val cl = ClassLoader.getSystemClassLoader
    val urls = cl.asInstanceOf[URLClassLoader].getURLs
    urls.foreach(url => println("Driver classpath is: " + url.getFile))

    val data = Array(1, 2, 3, 4, 5)
    val distData = sc.parallelize(data)
    distData.foreach(x=> RoundTripTester.test(x))
  }
}

在本地模式下,按照文档提交会在第 31 行生成“ClassNotFound”异常,其中 ClassToRoundTrip 对象被反序列化。奇怪的是,第28行的早期使用是可以的:

spark-submit --class "SimpleApp" \
             --master local[4] \
             target/scala-2.10/simpleapp_2.10-1.0.jar

但是,如果我为“driver-class-path”和“-jars”添加额外的参数,它可以在本地正常工作。

spark-submit --class "SimpleApp" \
             --master local[4] \
             --driver-class-path /home/xxxxxxx/workspace/SimpleApp/target/scala-2.10/simpleapp_2.10-1.0.jar \
             --jars /home/xxxxxxx/workspace/SimpleApp/target/scala-2.10/SimpleApp.jar \
             target/scala-2.10/simpleapp_2.10-1.0.jar

但是,提交给本地开发大师,仍然会产生同样的问题:

spark-submit --class "SimpleApp" \
             --master spark://localhost.localdomain:7077 \
             --driver-class-path /home/xxxxxxx/workspace/SimpleApp/target/scala-2.10/simpleapp_2.10-1.0.jar \
             --jars /home/xxxxxxx/workspace/SimpleApp/target/scala-2.10/simpleapp_2.10-1.0.jar \
             target/scala-2.10/simpleapp_2.10-1.0.jar

我可以从输出中看到执行程序正在获取 JAR 文件。

其中一位执行者的日志在这里:

标准输出:http://pastebin.com/raw.php?i=DQvvGhKm

标准错误:http://pastebin.com/raw.php?i=MPZZVa0Q

我使用的是 Spark 1.0.2。 ClassToRoundTrip 包含在 JAR 中。 我宁愿不必硬编码 SPARK_CLASSPATH 或 SparkContext.addJar 中的值。有人可以帮忙吗?

【问题讨论】:

  • 更新 - 我已经能够通过设置“spark.executor.extraClassPath”并使 JAR 文件在路径上的每个执行程序上本地可用来解决这个问题。我不明白为什么需要这样做:JAR 正在由执行程序从 Spark 的内部 HTTP 服务器获取并复制到每个执行程序的工作目录中。
  • 我今天看到了同样的问题。执行程序正在获取 Jar 并且它有它正在寻找的类,即使它抛出 ClassNotFoundException !我在 1.0.2 顺便说一句
  • 再次更新——我认为这可能与序列化有关。几天前我们发现更改序列化方法可以解决问题。我仍然不确定为什么,但值得一试。

标签: scala jar classpath apache-spark


【解决方案1】:

我也有同样的问题。如果 master 是本地的,那么程序对大多数人来说运行良好。如果他们将其设置为(也发生在我身上)“spark://myurl:7077”,它就不起作用。大多数人之所以会出错,是因为在执行期间未找到匿名类。它是通过使用 SparkContext.addJars ("Path to jar") 解决的。

确保您正在做以下事情:-

  • SparkContext.addJars("从 maven 创建的 jar 的路径 [hint: mvn package]").
  • 我在代码中使用了 SparkConf.setMaster("spark://myurl:7077"),并在通过命令行将作业提交给 spark 时提供了与参数相同的参数。
  • 当您在命令行中指定类时,请确保您使用 URL 编写它的完整名称。例如:“packageName.ClassName”
  • 最终命令应如下所示 bin/spark-submit --class "packageName.ClassName" --master spark://myurl:7077 pathToYourJar/target/yourJarFromMaven.jar

注意:最后一点的这个 jar pathToYourJar/target/yourJarFromMaven.jar 也是在代码中设置的,就像这个答案的第一点一样。

【讨论】:

【解决方案2】:

我也有同样的问题。我认为 --jars 不会将罐子运送给执行者。 在我将它添加到 SparkConf 后,它工作正常。

 val conf = new SparkConf().setMaster("...").setJars(Seq("/a/b/x.jar", "/c/d/y.jar"))

This web page for trouble shooting 也很有用。

【讨论】:

    【解决方案3】:

    你应该像这样在 spark-env.sh 文件中设置 SPARK_CLASS_PATH:

    SPARK_LOCAL_IP=your local ip 
    SPARK_CLASSPATH=your external jars
    

    你应该像这样使用 spark shell 提交:spark-submit --class your.runclass --master spark://yourSparkMasterHostname:7077 /your.jar

    你的java代码是这样的:

    SparkConf sparkconf = new SparkConf().setAppName("sparkOnHbase");  JavaSparkContext sc = new JavaSparkContext(sparkconf);
    

    然后它会工作。

    【讨论】:

      【解决方案4】:

      如果您使用 Maven 和 Maven Assembly 插件使用 mvn package 构建您的 jar 文件,请确保正确配置程序集插件以指向您的 Spark 应用程序的主类。

      应该将这样的内容添加到您的pom.xml 以避免任何java.lang.ClassNotFoundException 的:

                 <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-assembly-plugin</artifactId>
                  <version>2.4.1</version>
                  <configuration>
                      <archive>
                          <manifest>
                              <mainClass>com.my.package.SparkDriverApp</mainClass>
                          </manifest>
                      </archive>
                      <descriptorRefs>
                          <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                      <skipAssembly>false</skipAssembly>
                  </configuration>
                  <executions>
                      <execution>
                          <id>package</id>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
              </plugin>
      

      【讨论】:

        【解决方案5】:

        我发现如果您在构建项目时没有任何警告,那么您就不必为 master 和其他东西编写额外的代码。虽然这是一个很好的做法,但你可以避免它。就像我的情况一样,项目中没有警告,所以我能够在没有任何额外代码的情况下运行它。 Project Structure Link

        在我有一些与构建相关的警告的情况下,我必须处理 JAR 路径、我的 URL 和代码中的 master 以及在执行它时。

        我希望它可以帮助某人。干杯!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-08-26
          • 2017-12-25
          • 2017-11-24
          • 2019-11-13
          • 2020-04-05
          • 1970-01-01
          • 1970-01-01
          • 2016-09-04
          相关资源
          最近更新 更多