web-dev-qa-db-fra.com

Spark-submit ClassNotFoundexception

J'ai des problèmes avec une exception "ClassNotFound" en utilisant cet exemple simple:

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

En mode local, la soumission conformément à la documentation génère une exception "ClassNotFound" à la ligne 31, où l'objet ClassToRoundTrip est désérialisé. Étrangement, l’utilisation antérieure de la ligne 28 est acceptable:

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

Cependant, si j'ajoute des paramètres supplémentaires pour "driver-class-path" et "-jars", cela fonctionne correctement, en local. 

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

Cependant, la soumission à un maître de développement local génère toujours le même problème:

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

La sortie indique que le fichier JAR est en train d’être récupéré par l’exécuteur.

Les journaux de l'un des exécutants sont ici:

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

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

J'utilise Spark 1.0.2. Le ClassToRoundTrip est inclus dans le fichier JAR. Je préférerais ne pas avoir à coder en dur les valeurs dans SPARK_CLASSPATH ou SparkContext.addJar. Quelqu'un peut-il aider?

20
puppet

J'ai eu le même problème. Si master est local, le programme fonctionne correctement pour la plupart des gens. S'ils le configurent (cela m'est aussi arrivé) "spark: // myurl: 7077" si ne fonctionne pas. La plupart des gens obtiennent une erreur car une classe anonyme n'a pas été trouvée lors de l'exécution. Il est résolu en utilisant SparkContext.addJars ("Path to jar").

Assurez-vous que vous faites les choses suivantes: -

  • SparkContext.addJars ("chemin d'accès au fichier jar créé à partir de maven [indice: package mvn]}" ".
  • J'ai utilisé SparkConf.setMaster ("spark: // myurl: 7077") dans le code et j'ai fourni le même argument en soumettant le travail à déclencher via la ligne de commande.
  • Lorsque vous spécifiez la classe en ligne de commande, assurez-vous d’écrire son nom complet avec URL. par exemple: "packageName.ClassName"
  • La commande finale devrait ressembler à ceci Bin/spark-submit --class "packageName.ClassName" --master spark: // myurl: 7077pathToYourJar/target /votreJarFromMaven.jar

Remarque: le chemin jarToYourJar/target/yourJarFromMaven.jar dans le dernier point est également défini dans le code comme dans le premier point de cette réponse.

14
busybug91

J'ai aussi eu le même problème. Je pense que --jars n'envoie pas les pots aux exécuteurs . Après avoir ajouté ceci dans SparkConf, cela fonctionne bien.

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

Cette page Web pour le dépannage est également utile.

3
Yifei

Vous devez définir SPARK_CLASS_PATH dans spark-env.sh fichier comme ceci:

SPARK_LOCAL_IP=your local ip 
SPARK_CLASSPATH=your external jars

et vous devriez soumettre avec spark Shell comme ceci: spark-submit --class your.runclass --master spark://yourSparkMasterHostname:7077 /your.jar

et votre code Java comme ceci:

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

alors ça va marcher.

3
capotee

Si vous utilisez Maven et Maven Assembly plugin pour construire votre fichier jar avec mvn package, assurez-vous que le plug-in Assembly est correctement configuré pour pointer vers la classe principale de votre application Spark. 

Quelque chose comme ceci devrait être ajouté à votre pom.xml pour éviter tout 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>
1
jf2010

Ce que j'ai compris, c'est que si vous avez construit votre projet sans aucun avertissement, vous n'avez pas à écrire de code supplémentaire pour le maître et d'autres choses. Bien que ce soit une bonne pratique, vous pouvez simplement l'éviter. Comme ici dans mon cas, il n'y avait pas d'avertissement dans le projet, ce qui m'a permis de l'exécuter sans code supplémentaire. Lien vers la structure du projet

Dans le cas où j'ai des avertissements liés à la construction, je dois prendre en charge les chemins JAR, mon URL et le code maître ainsi que pendant son exécution. 

J'espère que cela peut aider quelqu'un. À votre santé !

0
RushHour