webentwicklung-frage-antwort-db.com.de

Spark-Submit ClassNotFoundexception

Ich habe Probleme mit einer "ClassNotFound" -Ausnahme mit diesem einfachen Beispiel:

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))
  }
}

Im lokalen Modus generiert das Senden gemäß den Dokumenten eine "ClassNotFound" -Ausnahme in Zeile 31, in der das ClassToRoundTrip-Objekt deserialisiert wird. Seltsamerweise ist der frühere Einsatz in Zeile 28 in Ordnung:

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

Wenn ich jedoch zusätzliche Parameter für "driver-class-path" und "-jars" hinzufüge, funktioniert dies auf lokalem Weg gut. 

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

Das Senden an einen lokalen Dev Master verursacht jedoch immer noch dasselbe Problem:

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

Ich kann aus der Ausgabe sehen, dass die JAR-Datei vom Executor abgerufen wird.

Protokolle für einen der Ausführenden sind hier:

stdout: http://Pastebin.com/raw.php?i=DQvvGhKm

stderr: http://Pastebin.com/raw.php?i=MPZZVa0Q

Ich verwende Spark 1.0.2. Der ClassToRoundTrip ist im JAR enthalten. Ich möchte lieber keine Werte in SPARK_CLASSPATH oder SparkContext.addJar festcodieren. Kann jemand helfen?

20
puppet

Ich hatte das gleiche Problem. Wenn der Master lokal ist, läuft das Programm für die meisten Leute gut. Wenn sie es auf (auch mir geschah) eingestellt haben, "spark: // myurl: 7077", wenn es nicht funktioniert. Die meisten Benutzer erhalten eine Fehlermeldung, weil während der Ausführung keine anonyme Klasse gefunden wurde. Es wird mit SparkContext.addJars ("Path to jar") aufgelöst.

Vergewissere dich, dass du folgende Dinge tust: -

  • SparkContext.addJars ("Pfad zu jar erstellt aus maven [Hinweis: mvn package]").
  • Ich habe SparkConf.setMaster ("spark: // myurl: 7077") im Code verwendet und dasselbe Argument angegeben, während der Job über die Befehlszeile an spark übergeben wird.
  • Wenn Sie in der Befehlszeile eine Klasse angeben, stellen Sie sicher, dass Sie den vollständigen Namen mit der URL schreiben. zB: "packageName.ClassName"
  • Der letzte Befehl sollte folgendermaßen aussehen Bin/spark-submit --class "packageName.ClassName" --master spark: // myurl: 7077pathToYourJar/target /yourJarFromMaven.jar

Hinweis: this jar pathToYourJar/target/yourJarFromMaven.jar im letzten Punkt wird auch wie im ersten Punkt dieser Antwort im Code festgelegt.

14
busybug91

Ich hatte auch das gleiche Problem. Ich denke, - jars liefert die Gläser nicht an Executoren ... Nachdem ich dies in SparkConf hinzugefügt habe, funktioniert es gut.

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

Diese Webseite zur Fehlersuche ist auch nützlich.

3
Yifei

Sie sollten die SPARK_CLASS_PATH-Datei in der Datei spark-env.sh wie folgt festlegen:

SPARK_LOCAL_IP=your local ip 
SPARK_CLASSPATH=your external jars

und Sie sollten mit spark Shell wie folgt einreichen: spark-submit --class your.runclass --master spark://yourSparkMasterHostname:7077 /your.jar

und dein Java-Code wie folgt:

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

dann wird es klappen.

3
capotee

Wenn Sie Maven und Maven Assembly plugin zum Erstellen Ihrer JAR-Datei mit mvn package verwenden, stellen Sie sicher, dass das Assembly-Plugin ordnungsgemäß konfiguriert ist, um auf die Hauptklasse Ihrer Spark-App zu verweisen. 

So etwas sollte zu Ihrem pom.xml hinzugefügt werden, um Java.lang.ClassNotFoundException's zu vermeiden:

           <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>
1
jf2010

Was ich herausgefunden habe war, wenn Sie Ihr Projekt ohne Warnungen erstellt haben, müssen Sie keinen zusätzlichen Code für Master und andere Dinge schreiben. Es ist zwar eine gute Praxis, aber Sie können es einfach vermeiden. Wie hier in meinem Fall gab es keine Warnungen im Projekt, sodass ich es ohne zusätzlichen Code ausführen konnte. Projektstrukturlink

Für den Fall, dass ich einige Build-bezogene Warnungen habe, muss ich mich um die JAR-Pfade, meine URL und den Master im Code sowie während der Ausführung kümmern. 

Ich hoffe es kann jemandem helfen. Prost !

0
RushHour