Mam problemy z „ClassNotFound” wyjątek przy użyciu tego prostego przykładu:Spark-submit ClassNotFound wyjątek
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))
}
}
W trybie lokalnym, składając zgodnie docs generuje „ClassNotFound” wyjątek na linii 31, gdzie obiekt ClassToRoundTrip jest deserialized. Co dziwne, wcześniej zastosowanie na linii 28 jest w porządku:
spark-submit --class "SimpleApp" \
--master local[4] \
target/scala-2.10/simpleapp_2.10-1.0.jar
Jednak jeśli dodać dodatkowe parametry dla „kierowca klasy ścieżce” i „-jars”, to działa dobrze, na poziomie lokalnym.
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
jednak złożenie do lokalnego mistrza dev, wciąż generuje ten sam 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
widzę z wyjścia, że plik JAR jest będącego pobierane przez Wykonawcę.
Logi do jednego z wykonawcą są tutaj:
stdout: http://pastebin.com/raw.php?i=DQvvGhKm
stderr: http://pastebin.com/raw.php?i=MPZZVa0Q
Używam Spark 1.0.2. ClassToRoundTrip jest zawarty w JAR. Wolałbym nie mieć wartości hardcode w SPARK_CLASSPATH lub SparkContext.addJar. Czy ktoś może pomóc?
Aktualizacja - udało mi się obejść to przez ustawienie«spark.executor.extraClassPath»i czyniąc Plik JAR lokalnie dostępny na każdym executorze znajdującym się na ścieżce. Nie rozumiem, dlaczego jest to potrzebne: JAR jest pobierany z wewnętrznego serwera HTTP Sparka przez executor i kopiowany do katalogu roboczego każdego executora. – puppet
Dzisiaj widzę ten sam problem. Słoik jest pobierany przez executora i ma klasę, której szuka, mimo że generuje wyjątek ClassNotFoundException !! Jestem na 1.0.2 btw – nir
Zaktualizuj ponownie - Myślę, że to może mieć coś wspólnego z serializacją. Znaleźliśmy kilka dni temu, że zmiana metody serializacji sprawiła, że problem zniknął. Wciąż nie jestem pewien dlaczego, ale warto spróbować. – puppet