《深刻理解Spark:核心思想與源碼分析》(前言及第1章)

 

  本身犧牲了7個月的週末和下班空閒時間,經過研究Spark源碼和原理,總結整理的《深刻理解Spark:核心思想與源碼分析》一書如今已經正式出版上市,目前亞馬遜、京東、噹噹、天貓等網站均有銷售,歡迎感興趣的同窗購買。我開始研究源碼時的Spark版本是1.2.0,通過7個多月的研究和出版社近4個月的流程,Spark自身的版本迭代也很快,現在最新已是1.6.0。目前市面上另外2本源碼研究的Spark書籍的版本分別是0.9.0版本和1.2.0版本,看來這些書的做者都與我同樣,遇到了這種問題。因爲研究和出版都須要時間,因此不能及時跟上Spark的腳步,還請你們見諒。可是Spark核心部分的變化相對仍是不多的,若是對版本不是過於追求,依然能夠選擇本書。html

 

 

京東:http://item.jd.com/11846120.html java

噹噹:http://product.dangdang.com/23838168.html linux

亞馬遜:http://www.amazon.cn/gp/product/B01A5G5LHK/sr=8-1/qid=1452505597/ref=olp_product_details?ie=UTF8&me=&qid=1452505597&sr=8-1git

 

爲了讓你們對本書有個大體瞭解,這裏將本書的前言及第一章的內容附上:github

 

前言 

爲何寫這本書 

         要回答這個問題,須要從我我的的經歷提及。說來慚愧,我第一次接觸計算機是在高三。當時跟你們一塊兒去網吧玩CS,跟身邊的同窗學怎麼「玩」。正是經過這種「玩」的過程,讓我瞭解到計算機並無那麼神祕,它也只是臺機器,用起來彷佛並不比打開電視機費勁多少。高考填志願的時候,憑着直覺「糊里糊塗」就選擇了計算機專業。等到真正學習計算機課程的時候卻又發現,它其實很難! shell

         早在2004年,還在學校的我跟不少同窗同樣,喜歡看Flash,也喜歡談論Flash甚至作Flash。感受Flash正如它的名字那樣「閃光」。那些年,在學校裏,知道Flash的人可要比知道Java的人多得多,這說明當時的Flash十分火熱。此外Oracle也成爲關係型數據庫裏的領軍人物,不少人甚至以爲懂Oracle要比懂Flash、Java及其它數據庫要厲害得多! 數據庫

         2007年,筆者剛剛參加工做不久。那時Struts一、Spring、Hibernate幾乎能夠稱爲那些用Java做爲開發語言的軟件公司的三駕馬車。很快隨着Struts2的誕生,很快替代了Struts1的地位,讓我第一次意識到IT領域的技術更新居然如此之快!隨着不少傳統軟件公司向互聯網公司轉型,更讓人吃驚的是,當初那個敢於技術更新的年輕人Gavin King,也許很難想象他創造的Hibernate也難以確保其地位,iBATIS誕生了! apache

         2010年,有關Hadoop的技術圖書涌入中國,當時不少公司用它只是爲了數據統計、數據挖掘或者搜索。一開始,人們對於Hadoop的認識和使用可能相對有限。大約2011年的時候,關於雲計算的概念在網上吵得火熱,當時依然在作互聯網開發的我,對其只是「道聽途說」。後來跟同事借了一本有關雲計算的書,回家挑着看了一些內容,以後什麼也沒有弄到手,悵然若失!上世紀60年代,美國的軍用網絡做爲互聯網的雛形,不少內容已經與雲計算中的某些說法相相似。到上世紀80年代,互聯網就已經開啓了雲計算,爲何現在又要重提這樣的概念?這個問題筆者可能回答不了,仍是交給歷史吧。 編程

         2012年,國內又呈現出大數據熱的態勢。從國家到媒體、教育、IT等幾乎全部領域,人人都在談大數據。個人親戚朋友中,不管老師、銷售仍是工程師們均可以對大數據談談本身的見解。我也找來一些Hadoop的書籍進行學習,但願能在其中探索到大數據的味道。 vim

         有幸在工做過程當中接觸到阿里的開放數據處理服務(Open Data Processing Service, 簡稱ODPS),而且基於ODPS與其餘小夥伴一塊兒構建阿里的大數據商業解決方案——御膳房。去杭州出差的過程當中,有幸認識和仲,跟他學習了阿里的實時多維分析平臺——Garuda和實時計算平臺——Galaxy的部分知識。和仲推薦我閱讀Spark的源碼,這樣會對實時計算及流式計算有更深刻的瞭解。2015年春節期間,本身初次上網查閱Spark的相關資料學習,開始研究Spark源碼。還記得那時只是出於對大數據的熱愛,想使本身在這方面的技術能力有所提高。 

         從閱讀Hibernate源碼開始,到後來閱讀Tomcat、Spring的源碼,隨着挖掘源碼,從學習源碼的過程當中成長,我對源碼閱讀也愈來愈感興趣。隨着對Spark源碼閱讀的深刻,發現不少內容從網上找不到答案,只能本身硬啃了。隨着本身的積累愈來愈多,忽然有天發現,我所總結的這些內容好像能夠寫成一本書了!從閃光(Flash)到火花(Spark),足足有11個年頭了。不管是Flash、Java,仍是Spring、iBATIS我一直扮演着一個追隨者,我接受這些書籍的洗禮,從未給予。現在我也是Spark的追隨者,不一樣的是,我再也不只想簡單的攫取,還要給予。 

         最後還想說下2016年是我從事IT工做的第十個年頭,此書特別做爲送給本身的十週年禮物。 

本書的主要特點 

  • 按照源碼分析的習慣設計,從腳本分析到初始化再到核心內容,最後介紹Spark的擴展內容。整個過程遵循由淺入深,由深到廣的基本思路。
  • 本書涉及的全部內容都有相應的例子,以便於對源碼的深刻研究能有更好的理解。
  • 本書儘量的用圖來展現原理,加速讀者對內容的掌握。
  • 本書講解的不少實現及原理都值得借鑑,能幫助讀者提高架構設計、程序設計等方面的能力。
  • 本書儘量保留較多的源碼,以便於初學者可以在脫離辦公環境的地方(如地鐵、公交),也能輕鬆閱讀。 

本書面向的讀者 

         源碼閱讀是一項苦差事,人力和時間成本都很高,尤爲是對於Spark陌生或者剛剛開始學習的人來講,難度可想而知。本書儘量保留源碼,使得分析過程不至於產生跳躍感,目的是下降大多數人的學習門檻。若是你是從事IT工做1~3年的新人或者但願開始學習Spark核心知識的人來講,本書很是適合你。若是你已經對Spark有所瞭解或者已經使用它,還想進一步提升本身,那麼本書更適合你。 

         若是你是一個開發新手,對Java、Linux等基礎知識不是很瞭解的話,本書可能不太適合你。若是你已經對Spark有深刻的研究,本書也許能夠做爲你的參考資料。 整體說來,本書適合如下人羣: 

  • 想要使用Spark,但對Spark實現原理不瞭解,不知道怎麼學習的人;
  • 大數據技術愛好者,以及想深刻了解Spark技術內部實現細節的人;
  • 有必定Spark使用基礎,可是不瞭解Spark技術內部實現細節的人;
  • 對性能優化和部署方案感興趣的大型互聯網工程師和架構師;
  • 開源代碼愛好者,喜歡研究源碼的同窗能夠從本書學到一些閱讀源碼的方式方法。 

         本書不會教你如何開發Spark應用程序,只是拿一些經典例子演示。本書會簡單介紹Hadoop MapReduce、Hadoop YARN、Mesos、Tachyon、ZooKeeper、HDFS、Amazon S3,但不會過多介紹這些等框架的使用,由於市場上已經有豐富的這類書籍供讀者挑選。本書也不會過多介紹Scala、Java、Shell的語法,讀者能夠在市場上選擇適合本身的書籍閱讀。本書實際適合那些想要破解一個個潘多拉魔盒的人! 

如何閱讀本書 

         本書分爲三大部分(不包括附錄): 

         第一部分爲準備篇(第1 ~ 2章),簡單介紹了Spark的環境搭建和基本原理,幫助讀者瞭解一些背景知識。 

         第二部分爲核心設計篇(第3 ~ 7章),着重講解SparkContext的初始化、存儲體系、任務提交與執行、計算引擎及部署模式的原理和源碼分析。 

         第三部分爲擴展篇(第8 ~ 11章),主要講解基於Spark核心的各類擴展及應用,包括:SQL處理引擎、Hive處理、流式計算框架Spark Streaming、圖計算框架GraphX、機器學習庫MLlib等內容。 

         本書最後還添加了幾個附錄,包括:附錄A介紹的Spark中最經常使用的工具類Utils;附錄B是Akka的簡介與工具類AkkaUtils的介紹;附錄C爲Jetty的簡介和工具類JettyUtils的介紹;附錄D爲Metrics庫的簡介和測量容器MetricRegistry的介紹;附錄E演示了Hadoop1.0版本中的word count例子;附錄F 介紹了工具類CommandUtils的經常使用方法;附錄G是關於Netty的簡介和工具類NettyUtils的介紹;附錄H列舉了筆者編譯Spark源碼時遇到的問題及解決辦法。 

         爲了下降讀者閱讀理解Spark源碼的門檻,本書儘量保留源碼實現,但願讀者可以懷着一顆好奇的心,Spark當前很火熱,其版本更新也很快,本書以Spark 1.2.3版本爲主,有興趣的讀者也可按照本書的方式,閱讀Spark的最新源碼。 

聯繫方式 

         本書內容不少,限於筆者水平有限,書中內容不免有錯誤之處。在本書出版的任什麼時候間,若是你對本書有任何問題或者意見均可以經過郵箱beliefer@163.com或者博客http://www.cnblogs.com/jiaan-geng/聯繫我,給我提交你的建議或者想法,我本人將懷着一顆謙卑之心與你們共同進步。 

致謝 

         感謝蒼天,讓我生活在這樣一個時代接觸互聯網和大數據;感謝父母,這麼多年來,在學習、工做及生活上的幫助與支持;感謝妻子在生活中的照顧和謙讓。 

         感謝楊福川編輯和高婧雅編輯給予本書出版的大力支持與幫助。 

         感謝冰夷老大和王賁老大讓我有幸加入阿里,接觸大數據應用;感謝和仲對Galaxy和Garuda耐心細緻的講解以及對Spark的推薦;感謝張中在百忙之中給本書寫評語;感謝周亮、澄蒼、民瞻、石申、清無、少俠、徵宇、三步、謝衣、曉5、法星、曦軒、九翎、峯閱、丁卯、阿末、紫丞、海炎、涵康、雲颺、孟天、零1、六仙、大知、井凡、隆君、太奇、晨炫、既望、寶升、都靈、鬼厲、歸鍾、梓撤、昊蒼、水村、惜冰、惜陌、元乾等同窗在工做上的支持和幫助。

耿嘉安

北京

 

 

第1章 環境準備

「凡事豫則立,不豫則廢;言前定,則不跲;事前定,則不困;」

——《禮記·中庸》

本章導讀:

  在深刻了解一個系統的原理、實現細節以前,應當先準備好它的源碼編譯環境、運行環境。若是能在實際環境安裝和運行Spark,顯然可以提高讀者對於Spark的一些感覺,對系統能有個大致的印象,有經驗的技術人員甚至可以猜出一些Spark採用的編程模型、部署模式等。當你經過一些途徑知道了系統的原理以後,難道不會問問本身?這是怎麼作到的。若是隻是遊走於系統使用、原理了解的層面,是永遠不可能真正理解整個系統的。不少IDE自己帶有調試的功能,每當你閱讀源碼,陷入重圍時,調試能讓咱們更加理解運行期的系統。若是沒有調試功能,不敢想象閱讀源碼的困難。

本章的主要目的是幫助讀者構建源碼學習環境,主要包括如下內容:

  1. 在windows環境下搭建源碼閱讀環境;
  2. 在Linux搭建基本的執行環境;
  3. Spark的基本使用,如spark-shell。

1.1 運行環境準備

    考慮到大部分公司在開發和生成環境都採用Linux操做系統,因此筆者選用了64位的Linux。在正式安裝Spark以前,先要找臺好機器。爲何?由於筆者在安裝、編譯、調試的過程當中發現Spark很是耗費內存,若是機器配置過低,恐怕會跑不起來。Spark的開發語言是Scala,而Scala須要運行在JVM之上,於是搭建Spark的運行環境應該包括JDK和Scala。

1.1.1 安裝JDK

    使用命令getconf LONG_BIT查看linux機器是32位仍是64位,而後下載相應版本的JDK並安裝。

下載地址:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

配置環境:

cd ~

vim .bash_profile

添加以下配置:

export JAVA_HOME=/opt/java

export PATH=$PATH:$JAVA_HOME/bin

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

因爲筆者的機器上已經安裝過openjdk,安裝命令:

$ su -c "yum install java-1.7.0-openjdk"

安裝完畢後,使用java –version命令查看,確認安裝正常,如圖1-1所示。

 

圖1-1  查看java安裝是否正常

1.1.2 安裝Scala

下載地址:http://www.scala-lang.org/download/

選擇最新的Scala版本下載,下載方法以下:

wget http://downloads.typesafe.com/scala/2.11.5/scala-2.11.5.tgz

移動到選好的安裝目錄,例如:

mv scala-2.11.5.tgz ~/install/

進入安裝目錄,執行如下命令:

chmod 755 scala-2.11.5.tgz

tar -xzvf scala-2.11.5.tgz

配置環境:

cd ~

vim .bash_profile

添加以下配置:

export SCALA_HOME=$HOME/install/scala-2.11.5

export PATH=$PATH:$SCALA_HOME/bin:$HOME/bin

安裝完畢後鍵入scala,進入scala命令行,如圖1-2所示。

 

圖1-2 進入Scala命令行

1.1.3安裝Spark

下載地址:http://spark.apache.org/downloads.html

選擇最新的Spark版本下載,下載方法以下:

wget http://archive.apache.org/dist/spark/spark-1.2.0/spark-1.2.0-bin-hadoop1.tgz

移動到選好的安裝目錄,如:

mv spark-1.2.0-bin-hadoop1.tgz~/install/

進入安裝目錄,執行如下命令:

chmod 755 spark-1.2.0-bin-hadoop1.tgz

tar -xzvf spark-1.2.0-bin-hadoop1.tgz

配置環境:

cd ~

vim .bash_profile

添加以下配置:

export SPARK_HOME=$HOME/install/spark-1.2.0-bin-hadoop1

1.2 Spark初體驗

本節經過Spark的基本使用,讓讀者對Spark能有初步的認識,便於引導讀者逐步深刻學習。

1.2.1 運行spark-shell

要運行spark-shell,須要先對Spark進行配置。

進入Spark的conf文件夾:

cd ~/install/spark-1.2.0-bin-hadoop1/conf

拷貝一份spark-env.sh.template,命名爲spark-env.sh,對它進行編輯,命令以下:

cp spark-env.sh.template spark-env.sh

vim spark-env.sh

添加以下配置:

export SPARK_MASTER_IP=127.0.0.1

export SPARK_LOCAL_IP=127.0.0.1

啓動spark-shell:

    cd ~/install/spark-1.2.0-bin-hadoop1/bin

    ./spark-shell

最後咱們會看到spark啓動的過程,如圖1-3所示:

 

圖1-3  Spark啓動過程

從以上啓動日誌中咱們能夠看到SparkEnv、MapOutputTracker、BlockManagerMaster、DiskBlockManager、MemoryStore、HttpFileServer、SparkUI等信息。它們是作什麼的?此處望文生義便可,具體內容將在後邊的章節詳細給出。

1.2.2 執行word count

這一節,咱們經過word count這個耳熟能詳的例子來感覺下Spark任務的執行過程。啓動spark-shell後,會打開Scala命令行,而後按照如下步驟輸入腳本:

步驟1   輸入val lines = sc.textFile("../README.md", 2),執行結果如圖1-4所示。

圖1-4    步驟1執行結果

步驟2   輸入val words = lines.flatMap(line => line.split(" ")),執行結果如圖1-5所示。

 

圖1-5   步驟2執行結果

步驟3   輸入val ones = words.map(w => (w,1)),執行結果如圖1-6所示。

 

圖1-6   步驟3執行結果

步驟4   輸入val counts = ones.reduceByKey(_ + _),執行結果如圖1-7所示。

 

圖1-7   步驟4執行結果

步驟5   輸入counts.foreach(println),任務執行過程如圖1-8和圖1-9所示。輸出結果如圖1-10所示。

 

圖1-8   步驟5執行過程部分

 

圖1-9   步驟5執行過程部分

 

圖1-10  步驟5輸出結果

在這些輸出日誌中,咱們先是看到Spark中任務的提交與執行過程,而後看到單詞計數的輸出結果,最後打印一些任務結束的日誌信息。有關任務的執行分析,筆者將在第5章中展開。

1.2.3 剖析spark-shell

經過word count在spark-shell中執行的過程,咱們想看看spark-shell作了什麼?spark-shell中有如下一段腳本,見代碼清單1-1。

 

代碼清單1-1     spark-shell

function main() {
  if $cygwin; then
stty -icanonmin 1 -echo > /dev/null 2>&1
    export SPARK_SUBMIT_OPTS="$SPARK_SUBMIT_OPTS -Djline.terminal=unix"
    "$FWDIR"/bin/spark-submit --class org.apache.spark.repl.Main "${SUBMISSION_OPTS[@]}" spark-shell "${APPLICATION_OPTS[@]}"
sttyicanon echo > /dev/null 2>&1
  else
    export SPARK_SUBMIT_OPTS
    "$FWDIR"/bin/spark-submit --class org.apache.spark.repl.Main "${SUBMISSION_OPTS[@]}" spark-shell "${APPLICATION_OPTS[@]}"
fi
}

 

咱們看到腳本spark-shell裏執行了spark-submit腳本,那麼打開spark-submit腳本,發現其中包含如下腳本。

exec "$SPARK_HOME"/bin/spark-class org.apache.spark.deploy.SparkSubmit "${ORIG_ARGS[@]}"

腳本spark-submit在執行spark-class腳本時,給它增長了參數SparkSubmit 。打開spark-class腳本,其中包含如下腳本,見代碼清單1-2。

 

代碼清單1-2     spark-class

if [ -n "${JAVA_HOME}" ]; then
  RUNNER="${JAVA_HOME}/bin/java"
else
  if [ `command -v java` ]; then
    RUNNER="java"
  else
    echo "JAVA_HOME is not set" >&2
    exit 1
  fi
fi

exec "$RUNNER" -cp "$CLASSPATH" $JAVA_OPTS "$@"

 

讀到這,應該知道Spark啓動了以SparkSubmit爲主類的jvm進程。

爲便於在本地可以對Spark進程使用遠程監控,給spark-class腳本增長追加如下jmx配置:

JAVA_OPTS="-XX:MaxPermSize=128m $OUR_JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10207 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

在本地打開jvisualvm,添加遠程主機,如圖1-11所示:

 

圖1-11  添加遠程主機

右鍵單擊已添加的遠程主機,添加JMX鏈接,如圖1-12:

 

圖1-12添加JMX鏈接

選擇右側的「線程」選項卡,選擇main線程,而後點擊「線程Dump」按鈕,如圖1-13。

圖1-13查看Spark線程

從dump的內容中找到線程main的信息如代碼清單1-3所示。

代碼清單1-3    main線程dump信息

"main" - Thread t@1
   java.lang.Thread.State: RUNNABLE
	at java.io.FileInputStream.read0(Native Method)
	at java.io.FileInputStream.read(FileInputStream.java:210)
	at scala.tools.jline.TerminalSupport.readCharacter(TerminalSupport.java:152)
	at scala.tools.jline.UnixTerminal.readVirtualKey(UnixTerminal.java:125)
	at scala.tools.jline.console.ConsoleReader.readVirtualKey(ConsoleReader.java:933)
	at scala.tools.jline.console.ConsoleReader.readBinding(ConsoleReader.java:1136)
	at scala.tools.jline.console.ConsoleReader.readLine(ConsoleReader.java:1218)
	at scala.tools.jline.console.ConsoleReader.readLine(ConsoleReader.java:1170)
	at org.apache.spark.repl.SparkJLineReader.readOneLine(SparkJLineReader.scala:80)
	at scala.tools.nsc.interpreter.InteractiveReader$class.readLine(InteractiveReader.scala:43)
	at org.apache.spark.repl.SparkJLineReader.readLine(SparkJLineReader.scala:25)
	at org.apache.spark.repl.SparkILoop.readOneLine$1(SparkILoop.scala:619)
	at org.apache.spark.repl.SparkILoop.innerLoop$1(SparkILoop.scala:636)
	at org.apache.spark.repl.SparkILoop.loop(SparkILoop.scala:641)
	at org.apache.spark.repl.SparkILoop$$anonfun$process$1.apply$mcZ$sp(SparkILoop.scala:968)
	at org.apache.spark.repl.SparkILoop$$anonfun$process$1.apply(SparkILoop.scala:916)
	at org.apache.spark.repl.SparkILoop$$anonfun$process$1.apply(SparkILoop.scala:916)
	at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
	at org.apache.spark.repl.SparkILoop.process(SparkILoop.scala:916)
	at org.apache.spark.repl.SparkILoop.process(SparkILoop.scala:1011)
	at org.apache.spark.repl.Main$.main(Main.scala:31)
	at org.apache.spark.repl.Main.main(Main.scala)
	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 org.apache.spark.deploy.SparkSubmit$.launch(SparkSubmit.scala:358)
	at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:75)
	at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

 

從main線程的棧信息中看出程序的調用順序:SparkSubmit.main→repl.Main→SparkILoop.process。SparkILoop.process方法中會調用initializeSpark方法,initializeSpark的實現見代碼清單1-4。

代碼清單1-4     initializeSpark的實現

def initializeSpark() {
intp.beQuietDuring {
      command("""
         @transient val sc = {
           val _sc = org.apache.spark.repl.Main.interp.createSparkContext()
           println("Spark context available as sc.")
           _sc
         }
        """)
      command("import org.apache.spark.SparkContext._")
    }
  }

 

咱們看到initializeSpark調用了createSparkContext方法,createSparkContext的實現,見代碼清單1-5。

代碼清單1-5    createSparkContext的實現

def createSparkContext(): SparkContext = {
val execUri = System.getenv("SPARK_EXECUTOR_URI")
val jars = SparkILoop.getAddedJars
val conf = new SparkConf()
      .setMaster(getMaster())
      .setAppName("Spark shell")
      .setJars(jars)
      .set("spark.repl.class.uri", intp.classServer.uri)
if (execUri != null) {
conf.set("spark.executor.uri", execUri)
    }
sparkContext = new SparkContext(conf)
    logInfo("Created spark context..")
sparkContext
  }

 

這裏最終使用SparkConf和SparkContext來完成初始化,具體內容將在「第3章SparkContext的初始化」講解。代碼分析中涉及的repl主要用於與Spark實時交互。

1.3 閱讀環境準備

準備Spark閱讀環境,一樣須要一臺好機器。筆者調試源碼的機器的內存是8GB。源碼閱讀的前提是首先在IDE環境中打包、編譯經過。經常使用的IDE有 IntelliJ IDEA、Eclipse,筆者選擇用Eclipse編譯Spark,緣由有二:一是因爲使用多年對它比較熟悉,二是社區中使用Eclipse編譯Spark的資料太少,在這裏能夠作個補充。筆者在windows系統編譯Spark源碼,除了安裝JDK外,還須要安裝如下工具。

(1)安裝Scala

因爲Spark 1.20版本的sbt裏指定的Scala版本是2.10.4,具體見Spark源碼目錄下的文件\project\plugins.sbt中,有一行:scalaVersion := "2.10.4"。因此選擇下載scala-2.10.4.msi,下載地址:http://www.scala-lang.org/download/

下載完畢,安裝scala-2.10.4.msi。

(2)安裝SBT

因爲Scala使用SBT做爲構建工具,因此須要下載SBT。下載地址: http://www.scala-sbt.org/,下載最新的安裝包sbt-0.13.8.msi並安裝。

(3)安裝Git Bash

         因爲Spark源碼使用Git做爲版本控制工具,因此須要下載Git的客戶端工具,筆者推薦使用Git Bash,由於它更符合Linux下的操做習慣。下載地址:http://msysgit.github.io/,下載最新的版本並安裝。

(4)安裝Eclipse Scala IDE插件

         Eclipse經過強大的插件方式支持各類IDE工具的集成,要在Eclipse中編譯、調試、運行Scala程序,就須要安裝Eclipse Scala IDE插件。下載地址:http://scala-ide.org/download/current.html

因爲筆者本地的Eclipse版本是Eclipse 4.4 (Luna),因此我選擇安裝插件http://download.scala-ide.org/sdk/lithium/e44/scala211/stable/site,如圖1-14:

 

圖1-14   Eclipse Scala IDE插件安裝地址

    在Eclipse中選擇「Help」菜單,而後選擇「Install New Software…」選項,打開Install對話框,如圖1-15所示: 

 

圖1-15  安裝Scala IDE插件

點擊「Add…」按鈕,打開「Add Repository」對話框,輸入插件地址,如1-16圖所示:

 

圖1-16  添加Scala IDE插件地址

全選插件的內容,完成安裝,如圖1-17所示:

 

圖1-17  安裝Scala IDE插件

1.4 Spark源碼編譯與調試

1.下載Spark源碼

首先,訪問Spark官網http://spark.apache.org/,如圖1-18所示:

 

圖1-18Spark官網

點擊「Download Spark」按鈕,在下一個頁面找到git地址,如圖1-19所示:

 

圖1-19  Spark官方git地址

打開Git Bash工具,輸入git clone git://github.com/apache/spark.git命令將源碼下載到本地,如1-20圖所示:

 

圖1-20下載Spark源碼

2.構建Scala應用

使用cmd命令行進到Spark根目錄,執行sbt命令。會下載和解析不少jar包,要等很長的時間,筆者大概花費了一個多小時,才執行完。

3.使用sbt生成eclipse工程文件

等sbt提高符>出現後,輸入eclipse命令,開始生成eclipse工程文件,也須要花費很長的時間,筆者本地大體花費了40分鐘。完成時的情況,如圖1-21所示:

 

圖1-21  sbt編譯過程

如今咱們查看Spark下的子文件夾,發現其中都生成了.project和.classpath文件。好比mllib項目下就生成了.project和.classpath文件,如圖1-22所示:

 

圖1-22sbt生成的項目文件

4.編譯Spark源碼

因爲Spark使用Maven做爲項目管理工具,因此須要將Spark項目做爲Maven項目導入到Eclipse中,如1-23圖所示:

 

圖1-23  導入Maven項目

點擊Next按鈕進入下一個對話框,如圖1-24所示:

 

圖1-24 選擇Maven項目

全選全部項目,點擊finish按鈕。這樣就完成了導入,如圖1-25所示:

 

圖1-25 導入完成的項目

導入完成後,須要設置每一個子項目的build path。右鍵單擊每一個項目,選擇「Build Path」→「Configure Build Path…」,打開Build Path對話框,如圖1-26:

 

圖1-26 Java編譯目錄

點擊「Add External JARs…」按鈕,將Spark項目下的lib_managed文件夾的子文件夾bundles和jars內的jar包添加進來。


注意:lib_managed/jars文件夾下有不少打好的spark的包,好比:spark-catalyst_2.10-1.3.2-SNAPSHOT.jar。這些jar包有可能與你下載的Spark源碼的版本不一致,致使你在調試源碼時,發生jar包衝突。因此請將它們排除出去。


 

Eclipse在對項目編譯時,筆者本地出現了不少錯誤,有關這些錯誤的解決見附錄H。全部錯誤解決後運行mvn clean install,如圖1-27所示:

 

圖1-27 編譯成功

5.調試Spark源碼

         以Spark源碼自帶的JavaWordCount爲例,介紹如何調試Spark源碼。右鍵單擊JavaWordCount.java,選擇「Debug As」→「Java Application」便可。若是想修改配置參數,右鍵單擊JavaWordCount.java,選擇「Debug As」→「Debug Configurations…」,從打開的對話框中選擇JavaWordCount,在右側標籤能夠修改Java執行參數、JRE、classpath、環境變量等配置,如圖1-28所示:

 

圖1-28源碼調試

讀者也能夠在Spark源碼中設置斷點,進行跟蹤調試。

1.5 小結

         本章經過引導你們在Linux操做系統下搭建基本的執行環境,而且介紹spark-shell等腳本的執行,目的沒法是爲了幫助讀者由淺入深的進行Spark源碼的學習。因爲目前多數開發工做都在Windows系統下,而且Eclipse有最廣大的用戶羣,即使是一些開始使用IntelliJ的用戶對Eclipse也不陌生,因此在Windows環境下搭建源碼閱讀環境時,選擇這些最經常使用的工具,但願能下降讀者的學習門檻,而且替你們節省時間。

相關文章
相關標籤/搜索