Spark-submit Исключение класса ClassNotFound

У меня возникли проблемы с Exception 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))
  }
}

В локальном режиме отправка в соответствии с документами генерирует исключение ClassNotFound в строке 31, где объект ClassToRoundTrip десериализуется. Как ни странно, более раннее использование в строке 28 в порядке:

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

Однако, если я добавляю дополнительные параметры для "path-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

Однако при отправке в локальный мастер-dev по-прежнему возникает одна и та же проблема:

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 файл извлекается исполнителем.

Журналы для одного из исполнителей:

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

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

Я использую Spark 1.0.2. ClassToRoundTrip включен в JAR. Я бы предпочел не иметь hardcode значения в SPARK_CLASSPATH или SparkContext.addJar. Может ли кто-нибудь помочь?

Ответы

Ответ 1

У меня была такая же проблема. Если мастер является локальным, программа работает отлично для большинства людей. Если они установили его (также случилось со мной), "spark://myurl: 7077", если не работает. Большинство людей получают ошибку, потому что анонимный класс не был найден во время выполнения. Он разрешен с помощью SparkContext.addJars( "Путь к jar" ).

Убедитесь, что вы выполняете следующие действия: -

  • SparkContext.addJars( "Путь к jar, созданный с помощью maven [hint: mvn package]" ).
  • Я использовал SparkConf.setMaster( "spark://myurl: 7077" ) в коде и предоставил тот же аргумент при отправке задания в исправную строку из командной строки.
  • Когда вы указываете класс в командной строке, убедитесь, что вы написали его полное имя с 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"))

Эта страница для устранения неполадок также полезна.

Ответ 3

Вы должны установить SPARK_CLASS_PATH в файле spark-env.sh следующим образом:

SPARK_LOCAL_IP=your local ip 
SPARK_CLASSPATH=your external jars

и вы должны отправить с помощью искровой оболочки следующим образом: 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 для создания вашего файла jar с помощью mvn package, убедитесь, что плагин сборки настроен правильно чтобы указать на основной класс приложения 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>