天天看點

spark-shell腳本分析spark-shellspark-submitspark-class

本文主要分析spark-shell腳本的運作邏輯,涉及到spark-submit、spark-class等腳本的分析,希望通過分析腳本以了解spark中各個程序的參數、jvm參數和記憶體大小如何設定。

使用yum安裝spark之後,你可以直接在終端運作spark-shell指令,或者在spark的home目錄/usr/lib/spark下運作bin/spark-shell指令,這樣就可以進入到spark指令行互動模式。

spark-shell 腳本是如何運作的呢?該腳本代碼如下:

從上往下一步步分析,首先是判斷是否為cygwin,這裡用到了bash中的<code>case</code>文法:

在linux系統中,<code>uname</code>指令的運作結果為linux,其值不等于<code>cygwin*</code>,故cygwin=false。

開啟bash的posix模式:

擷取上級目錄絕對路徑,這裡使用到了<code>dirname</code>指令:

提示:bash 中,$0 是擷取腳本名稱

判斷輸入參數中是否有<code>--help</code>或者<code>-h</code>,如果有,則列印使用說明,實際上運作的是<code>/bin/spark-submit --help</code>指令:

提示: 2&gt;&amp;1 的意思是将标準錯誤也輸出到标準輸出當中;1&gt;&amp;2是将标準輸出輸出到标準錯誤當中 bash 中,$@ 是擷取腳本所有的輸入參數

再往後面是定義了一個main方法,并将spark-shell的輸入參數傳給該方法運作,main方法中判斷是否是cygwin模式,如果不是,則運作

提示:”${submission_opts[@]}” 這是什麼意思?

從上面可以看到,其實最後調用的是spark-submit指令,并指定<code>--class</code>參數為<code>org.apache.spark.repl.main</code>類,後面接的是spark-submit的送出參數,再後面是spark-shell,最後是傳遞應用的參數。

最後,是擷取main方法運作結果:

提示: bash 中,<code>$?</code>是擷取上個指令運作結束傳回的狀态碼

如果以調試模式運作spark-shell,在不加參數的情況下,輸出内容為:

提示:通過運作<code>set -x</code>可以開啟bash調試代碼的特性。

接下來就涉及到spark-submit指令的邏輯了。

完整的spark-submit腳本内容如下:

首先是設定<code>spark_home</code>,并保留原始輸入參數:

接下來,使用while語句配合<code>shift</code>指令,依次判斷輸入參數。

說明:shift是将輸入參數位置向左移位

設定<code>spark_conf_dir</code>變量,并判斷spark-submit部署模式。

如果<code>$spark_conf_dir/spark-defaults.conf</code>檔案存在,則檢查是否設定<code>spark.driver.extra</code>開頭的和<code>spark.driver.memory</code>變量,如果設定了,則<code>spark_submit_bootstrap_driver</code>設為1。

最後,執行的是spark-class指令,輸入參數為<code>org.apache.spark.deploy.sparksubmit</code>類名和原始參數。

該腳本首先還是判斷是否是cygwin,并設定spark_home和spark_conf_dir變量。

運作bin/load-spark-env.sh,加載spark環境變量。

spark-class至少需要傳遞一個參數,如果沒有,則會列印腳本使用說明<code>usage: spark-class &lt;class&gt; [&lt;args&gt;]</code>。

如果設定了<code>spark_mem</code>變量,則提示<code>spark_mem</code>變量過時,應該使用<code>spark.executor.memory</code>或者<code>spark.driver.memory</code>變量。

設定預設記憶體<code>default_mem</code>為512m,如果<code>spark_mem</code>變量存在,則使用<code>spark_mem</code>的值。

使用case語句判斷spark-class傳入的第一個參數的值:

可能存在以下幾種情況:

<code>org.apache.spark.deploy.master.master</code>

<code>org.apache.spark.deploy.worker.worker</code>

<code>org.apache.spark.deploy.history.historyserver</code>

<code>org.apache.spark.executor.coarsegrainedexecutorbackend</code>

<code>org.apache.spark.executor.mesosexecutorbackend</code>

<code>org.apache.spark.deploy.sparksubmit</code>

并分别設定每種情況下的java運作參數和使用記憶體大小,以表格形式表示如下:

our_java_opts

our_java_mem

master

$spark_daemon_java_opts $spark_master_opts

${spark_daemon_memory:-$default_mem}

worker

$spark_daemon_java_opts $spark_worker_opts

historyserver

$spark_daemon_java_opts $spark_history_opts

coarsegrainedexecutorbackend

$spark_java_opts $spark_executor_opts

${spark_executor_memory:-$default_mem}

mesosexecutorbackend

sparksubmit

$spark_java_opts $spark_submit_opts

${spark_driver_memory:-$default_mem}

通過上表就可以知道每一個spark中每個程序如何設定jvm參數和記憶體大小。

接下來是查找java_home并檢查java版本。

設定spark_tools_jar變量。

運作bin/compute-classpath.sh計算classpath。

判斷<code>spark_submit_bootstrap_driver</code>變量值,如果該值為1,則運作<code>org.apache.spark.deploy.sparksubmitdriverbootstrapper</code>類,以替換原來的<code>org.apache.spark.deploy.sparksubmit</code>的類,執行的腳本為<code>exec "$runner" org.apache.spark.deploy.sparksubmitdriverbootstrapper "$@"</code>;否則,運作java指令<code>exec "$runner" -cp "$classpath" $java_opts "$@"</code>。

從最後運作的腳本可以看到,spark-class腳本的作用主要是查找java指令、計算環境變量、設定<code>java_opts</code>等,至于運作的是哪個java類的main方法,取決于<code>spark_submit_bootstrap_driver</code>變量的值。

接下來,就是要分析<code>org.apache.spark.deploy.sparksubmitdriverbootstrapper</code>和<code>org.apache.spark.deploy.sparksubmit</code>類的運作邏輯以及兩者之間的差別,這部分内容見下篇文章。