1. 程式人生 > >Spark開發中遇到的問題及解決方法

Spark開發中遇到的問題及解決方法

1.Windows下執行spark產生的Failed to locate the winutils binary in the hadoop binary path異常
解決方法:

1.下載winutils的windows版本
  GitHub上,有人提供了winutils的windows的版本,專案地址是:https://github.com/srccodes/hadoop-common-2.2.0-bin,直接下載此專案的zip包,下載後是檔名是hadoop-common-2.2.0-bin-master.zip,隨便解壓到一個目錄
  2.配置環境變數
  增加使用者變數HADOOP_HOME,值是下載的zip包解壓的目錄,然後在系統變數path裡增加$HADOOP_HOME\bin 即可。  
  再次執行程式,正常執行。

2.在Spark中,要訪問hdfs檔案系統上的檔案,需要將hadoop的core-site.xml和hdfs-site.xml兩個檔案拷貝到spark的conf目錄下

3.Spark引入第三方Jar包的問題
①可以使用maven的assembly外掛將第三方Jar包全部打入生成的Jar中,存在的問題是Jar生成慢,生成的Jar包很大
②在spark-submit時新增–jars引數,問題是引入的Jar包比較多時,命令列比較長

spark-submit --jars ~/lib/hanlp-1.5.3.jar  --class "www.bdqn.cn.MyTest" --master spark://hadoop000:7077 ~/lib/SparkTechCount-1.0.jar

③配置spark的spark-defaults.conf設定第三方Jar包的目錄,不過此種情況下叢集上的每臺機器都需要配置並上傳Jar包

spark.executor.extraClassPath=/home/hadoop/app/spark-1.6.3-bin-hadoop2.6/external_jars/*
spark.driver.extraClassPath=/home/hadoop/app/spark-1.6.3-bin-hadoop2.6/external_jars/*

④在spark on yarn(cluster)模式下,可以將Jar包放到hdfs上,由於沒有親自測試,只是在此記錄下。

3.Spark的檔案系統在分散式環境下也使用的是HDFS,我的實驗機在經過了1個週末後使用Xshell登入伺服器後,發現在命令列模式下輸入都卡頓。原因在網上查了下是因為hdfs的問題,先記錄解決辦法:
①此時使用stop-all.sh指令碼已經無法停止hdfs了
②使用命令列查詢Hadoop相關的程序號:

ps -ef | grep java | grep hadoop

然後使用kill xxxx把對應的程序一個一個的殺掉,我殺程序是從上到下挨個殺的,網上找到的資料有寫殺程序的順序應按照以下順序,可以參考:

停止順序: job 、task、namenode、datanode、secondarynode

③殺完程序後,再使用start-all.sh和stop-all.sh就可以了。
④在網上找到的永久解決方案,嘗試效果待驗證

出現這個問題的最常見原因是hadoop在stop的時候依據的是datanode上的mapred和dfs程序號。而預設的程序號儲存在/tmp下,linux預設會每隔一段時間(一般是一個月或者7天左右)去刪除這個目錄下的檔案。因此刪掉hadoop-hadoop-jobtracker.pid和hadoop-hadoop-namenode.pid兩個檔案後,namenode自然就找不到datanode上的這兩個程序了。
另外還有兩個原因可能引起這個問題:
①:環境變數 $HADOOP_PID_DIR 在你啟動hadoop後改變了
②:用另外的使用者身份執行stop-all
解決方法:
①:永久解決方法,修改$HADOOP_HOME/conf/hadoop-env.sh裡邊,去掉export HADOOP_PID_DIR=/var/hadoop/pids的#號,建立/var/hadoop/pids或者你自己指定目錄
發現問題後的解決方法:
①:這個時候通過指令碼已經無法停止程序了,不過我們可以手工停止,方法是到各mfs master和各datanode執行ps -ef | grep java | grep hadoop找到程序號強制殺掉,然後在master執行start-all指令碼重新啟動,就能正常啟動和關閉了。

我把HADOOP_PID_DIR指定為

export HADOOP_PID_DIR=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0/pids

4.Spark開發時遇到這個Exception:

Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 0.0 in stage 2.0 (TID 2) had a not serializable result: java.util.ArrayList$SubList
Serialization stack:
    - object not serializable (class: java.util.ArrayList$SubList, value: [d])
    - field (class: scala.Tuple3, name: _2, type: class java.lang.Object)
    - object (class scala.Tuple3, ([a, b],[d],0.5))
    - writeObject data (class: java.util.ArrayList)
    - object (class java.util.ArrayList, [([a, b],[d],0.5), ([a, b],[c],0.5)])
    - element of array (index: 0)
    - array (class [Ljava.lang.Object;, size 11)
    at org.apache.spark.scheduler.DAGScheduler.org$apache$spark$scheduler$DAGScheduler$$failJobAndIndependentStages(DAGScheduler.scala:1431)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1419)
    at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1418)
	at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
	at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
	at org.apache.spark.scheduler.DAGScheduler.abortStage(DAGScheduler.scala:1418)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:799)
    at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:799)
	at scala.Option.foreach(Option.scala:236)
	at org.apache.spark.scheduler.DAGScheduler.handleTaskSetFailed(DAGScheduler.scala:799)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.doOnReceive(DAGScheduler.scala:1640)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1599)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1588)
	at org.apache.spark.util.EventLoop$$anon$1.run(EventLoop.scala:48)
    at org.apache.spark.scheduler.DAGScheduler.runJob(DAGScheduler.scala:620)
    at org.apache.spark.SparkContext.runJob(SparkContext.scala:1832)
    at org.apache.spark.SparkContext.runJob(SparkContext.scala:1845)
    at org.apache.spark.SparkContext.runJob(SparkContext.scala:1858)
    at org.apache.spark.SparkContext.runJob(SparkContext.scala:1929)
    at org.apache.spark.rdd.RDD$$anonfun$collect$1.apply(RDD.scala:927)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:150)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:111)
    at org.apache.spark.rdd.RDD.withScope(RDD.scala:316)
    at org.apache.spark.rdd.RDD.collect(RDD.scala:926)
    at org.apache.spark.api.java.JavaRDDLike$class.collect(JavaRDDLike.scala:339)
    at org.apache.spark.api.java.AbstractJavaRDDLike.collect(JavaRDDLike.scala:46)
    at org.dataalgorithms.MyImplementation.MarketBasketAnalyzeDriver.main(MarketBasketAnalyzeDriver.java:106)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

原因是我在Spark程式碼裡呼叫了subList來獲得List子串,解決方案如下
At some point you’re using something like: x
= myArrayList.subList(a,b));

After this x will not be serializable as the sublist object returned from subList() does not implement it. Try doing x
= new ArrayList(myArrayList.subList(a,b))); instead.