web-dev-qa-db-ja.com

Spark-submit ClassNotFoundexception

この簡単な例を使用して、「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))
  }
}

ローカルモードでは、ドキュメントに従って送信すると、ClassToRoundTripオブジェクトが逆シリアル化される31行目に「ClassNotFound」例外が生成されます。奇妙なことに、28行目の以前の使用は問題ありません。

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

ただし、「driver-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

ただし、ローカルの開発マスターに送信しても、同じ問題が発生します。

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ファイルがエグゼキューターによってフェッチされていることがわかります。

いずれかのエグゼキューターのログは次のとおりです。

標準出力: http://Pastebin.com/raw.php?i=DQvvGhKm

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

Spark1.0.2。ClassToRoundTripはJARに含まれています。SPARK_CLASSPATHまたはSparkContext.addJarに値をハードコーディングする必要はありません。誰でも助けてもらえますか?

21
puppet

これと同じ問題がありました。マスターがローカルの場合、ほとんどの人にとってプログラムは正常に実行されます。彼らがそれを設定した場合(私にも起こった)「spark:// myurl:7077」が機能しない場合。実行中に匿名クラスが見つからなかったため、ほとんどの人がエラーを受け取ります。 SparkContext.addJars( "Path to jar")を使用して解決します。

次のことを行っていることを確認してください:-

  • SparkContext.addJars( "mavenから作成されたjarへのパス[ヒント:mvnパッケージ]")。
  • コードでSparkConf.setMaster( "spark:// myurl:7077")を使用し、sparkコマンドライン経由。
  • コマンドラインでクラスを指定するときは、URLを含む完全な名前を書いていることを確認してください。例: "packageName.ClassName"
  • 最終的なコマンドは次のようになりますbin/spark-submit --class "packageName.ClassName"--masterspark :// myurl:7077pathToYourJar/target/yourJarFromMaven.jar

注:最後のポイントのこのjar pathToYourJar/target/yourJarFromMaven.jarも、この回答の最初のポイントのようにコードで設定されます。

15
busybug91

私も同じ問題を抱えていました。 --jarsはjarをエグゼキューターに出荷していないと思います。これをSparkConfに追加すると、正常に機能します。

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

トラブルシューティング用のこのWebページ も便利です。

3
Yifei

次のようにspark-env.shファイルでSPARK_CLASS_PATHを設定する必要があります。

SPARK_LOCAL_IP=your local ip 
SPARK_CLASSPATH=your external jars

そしてspark Shell like this:spark-submit --class your.runclass --master spark://yourSparkMasterHostname:7077 /your.jar

そして、あなたのJavaこのようなコード:

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

その後、動作します。

3
capotee

Mavenおよび Maven Assembly プラグインを使用してmvn packageでjarファイルをビルドする場合は、Sparkアプリのメインクラスを指すようにAssemblyプラグインが正しく構成されていることを確認してください。

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

私が考え出したのは、警告なしでプロジェクトをビルドすれば、マスターなどのために余分なコードを書く必要はないということです。それは良い習慣ですが、それを避けることができます。私の場合のように、プロジェクトには警告がなかったため、余分なコードなしで実行できました。 プロジェクト構造リンク

ビルド関連の警告がいくつかある場合は、JARパス、URL、およびコード内のマスターを、実行中に注意する必要があります。

誰かの助けになることを願っています。乾杯!

0
RushHour