Apache Spark技術實戰之6 -- spark-submit常見問題及其解決

徽滬一郎發表於2014-10-26

除本人同意外,嚴禁一切轉載,徽滬一郎。

概要

編寫了獨立執行的Spark Application之後,需要將其提交到Spark Cluster中執行,一般會採用spark-submit來進行應用的提交,在使用spark-submit的過程中,有哪些事情需要注意的呢?

本文試就此做一個小小的總結。

spark-defaults.conf

Spark-defaults.conf的作用範圍要搞清楚,編輯driver所在機器上的spark-defaults.conf,該檔案會影響 到driver所提交執行的application,及專門為該application提供計算資源的executor的啟動引數

只需要在driver所在的機器上編輯該檔案,不需要在worker或master所執行的機器上編輯該檔案

舉個實際的例子

spark.executor.extraJavaOptions	   -XX:MaxPermSize=896m
spark.executor.memory		   5g
spark.serializer        org.apache.spark.serializer.KryoSerializer
spark.cores.max		32
spark.shuffle.manager	SORT
spark.driver.memory	2g

 上述配置表示為該application提供計算資源的executor啟動時, heap memory需要有5g。

這裡需要引起注意的是,如果worker在加入cluster的時候,申明自己所在的機器只有4g記憶體,那麼為上述的application分配executor是,該worker不能提供任何資源,因為4g<5g,無法滿足最低的資源需求。

spark-env.sh

spark-env.sh中最主要的是指定ip地址,如果執行的是master,就需要指定SPARK_MASTER_IP,如果準備執行driver或worker就需要指定SPARK_LOCAL_IP,要和本機的IP地址一致,否則啟動不了。

配置舉例如下

export SPARK_MASTER_IP=127.0.0.1
export SPARK_LOCAL_IP=127.0.0.1

啟動spark叢集

第一步啟動master

$SPARK_HOME/sbin/start-master.sh

第二步啟動worker

$SPARK_HOME/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077

將master替換成MASTER實際執行的ip地址

如果想在一臺機器上執行多個worker(主要是用於測試目的),那麼在啟動第二個及後面的worker時需要指定—webui-port的內容,否則會報埠已經被佔用的錯誤,啟動第二個用的是8083,第三個就用8084,依此類推。

$SPARK_HOME/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077
    –webui-port 8083

 這種啟動worker的方式只是為了測試是啟動方便,正規的方式是用SPARK_HOME/sbin/start-slaves.sh來啟動多個worker,由於涉及到ssh的配置,比較麻煩,我這是圖簡單的辦法。

用$SPARK\_HOME/sbin/start-slave.sh$來啟動worker時有一個預設的前提,即在每臺機器上$SPARK_HOME必須在同一個目錄。

使用相同的使用者名稱和使用者組來啟動Master和Worker,否則Executor在啟動後會報連線無法建立的錯誤。

我在實際的使用當中,遇到”no route to host”的錯誤資訊,起初還是認為網路沒有配置好,後來網路原因排查之後,忽然意識到有可能使用了不同的使用者名稱和使用者組,使用相同的使用者名稱/使用者組之後,問題消失。

spark-submit

spark叢集執行正常之後,接下來的問題就是提交application到叢集執行了。

Spark-submit用於Spark application的提交和執行,在使用這個指令的時候最大的困惑就是如何指定應用所需要的依賴包。

首先檢視一下spark-submit的幫助檔案

$SPARK_HOME/bin/submit --help

有幾個選項可以用來指定所依賴的庫,分別為

  • --driver-class-path driver所依賴的包,多個包之間用冒號(:)分割
  • --jars   driver和executor都需要的包,多個包之間用逗號(,)分割

為了簡單起見,就通過—jars來指定依賴,執行指令如下

$SPARK_HOME/bin/spark-submit –class 應用程式的類名 \
--master spark://master:7077 \
--jars 依賴的庫檔案 \
spark應用程式的jar包

需要提醒的時,這些上傳到worker的檔案,需要定時做手工清理,否則會佔用許多磁碟空間

問題1

由於Spark在計算的時候會將中間結果儲存到/tmp目錄,而目前linux又都支援tmpfs,其實說白了就是將/tmp目錄掛載到記憶體當中。

那麼這裡就存在一個問題,中間結果過多導致/tmp目錄寫滿而出現如下錯誤

No Space Left on the device

解決辦法就是針對tmp目錄不啟用tmpfs,修改/etc/fstab

問題2

有時可能會遇到java.lang.OutOfMemory, unable to create new native thread的錯誤,導致這種錯誤的原因比較多。

有一種情況並非真的是記憶體不足引起的,而是由於超出了允許的最大檔案控制程式碼數或最大程式數。

排查的步驟就是檢視一下允許開啟的檔案控制程式碼數和最大程式數,如果數值過低,使用ulimit將其調高之後,再試試問題是否已經解決。

ulimit -a

修改允許開啟的最大程式數

ulimit -u 65535

修改允許開啟的檔案控制程式碼

ulimit -n 65535

spark-shell

上面講述了spark-submit提交Spark Application如何解決依賴庫的問題,那如果是spark-shell的話,該怎麼辦呢?

spark-shell的話,利用--driver-class-path選項來指定所依賴的jar檔案,注意的是--driver-class-path後如果需要跟著多個jar檔案的話,jar檔案之間使用冒號(:)來分割。

小結

本文部分內容已由本人徽滬一郎在CSDN中通過”使用Spark+Cassandra打造高效能資料分析平臺“發表。

相關文章