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?
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: -
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.
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.
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.
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>
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é !