2014-09-05 119 views
15

我在與使用這個簡單的例子是「ClassNotFound的」異常的問題:火花提交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)) 
    } 
} 

在本地模式下,提交按照該文檔生成上線31是「ClassNotFound的」異常, ClassToRoundTrip對象被反序列化。奇怪的是,第28行較早的使用是好的:

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

不過,如果我添加爲「驅動程序類路徑」額外的參數,和「-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

標準錯誤:http://pastebin.com/raw.php?i=MPZZVa0Q

我使用星火1.0.2。 ClassToRoundTrip包含在JAR中。 我寧願不必硬編碼SPARK_CLASSPATH或SparkContext.addJar中的值。誰能幫忙?

+2

更新 - 我已經能夠通過設置‘spark.executor.extraClassPath’,並作出解決此JAR文件在路徑上的每個執行程序的本地可用。我不明白爲什麼需要這樣做:JAR由執行程序從Spark的內部HTTP服務器提取並複製到每個執行程序的工作目錄中。 – puppet 2014-09-08 14:37:52

+0

今天我看到同樣的問題。 Jar正在被執行程序取回,並且它有類查找,即使它拋出ClassNotFoundException!我在1.0.2 btw – nir 2014-11-06 20:40:59

+0

再次更新 - 我認爲這可能與序列化有關。幾天前我們發現改變序列化方法使問題消失。我仍然不確定爲什麼,但值得一試。 – puppet 2014-11-08 19:46:37

回答

12

我有這個相同的問題。如果主人是本地人,那麼程序對大多數人來說運行良好如果它們設置爲(也發生在我身上)「spark:// myurl:7077」如果不起作用。大多數人都會遇到錯誤,因爲在執行過程中沒有找到匿名類。它通過使用SparkContext.addJars(「路徑到jar」)來解決。

確保你正在做以下的事情: -

  • SparkContext.addJars( 「路徑從行家創建[提示:MVN包]罐子」)。
  • 我在代碼中使用了SparkConf.setMaster(「spark:// myurl:7077」),並通過命令行提供了相同的參數。
  • 當您在命令行中指定類時,請確保您正在使用URL編寫完整的名稱。如:「packageName.ClassName」
  • 最後的命令應該是這樣的 斌/火花提交--class 「packageName.ClassName」 --master 火花:// myurl:7077pathToYourJar /目標/yourJarFromMaven.jar

注:這個罐子pathToYourJar /目標/ yourJarFromMaven.jar在最後一點也是在代碼中設置爲這個答案的第一站。

+0

這個鏈接是無價的 - http://www.datastax.com/dev/blog/common-spark-troubleshooting;請注意,如果您不打算將依賴關係複製到所有節點,則需要包含'fat'jar。請點擊此處查看如何使用sbt構建一個:assembly http://stackoverflow.com/questions/28459333/how-to-build-an-uber-jar-fat-jar-using-sbt-within-intellij-idea – 2016-06-13 12:03:44

3

我也有同樣的問題。我認爲 - 罐子不是將罐子運送給執行者。 當我將此添加到SparkConf後,它工作正常。

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

This web page for trouble shooting也很有用。

3

你應該這樣設置在spark-env.sh文件SPARK_CLASS_PATH:

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

然後它會工作。

0

如果您使用Maven和Maven Assembly插件與mvn package一起構建您的jar文件,請確保程序集插件配置正確,以指向您的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>