《深入理解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核心部分的變化相對還是很少的,如果對版本不是過於追求,依然可以選擇本書。

 

 

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

當當:http://product.dangdang.com/23838168.html 

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

 

為了讓大家對本書有個大致了解,這里將本書的前言及第一章的內容附上:

 

前言 

為什么寫這本書 

         要回答這個問題,需要從我個人的經歷說起。說來慚愧,我第一次接觸計算機是在高三。當時跟大家一起去網吧玩CS,跟身邊的同學學怎么“玩”。正是通過這種“玩”的過程,讓我了解到計算機並沒有那么神秘,它也只是台機器,用起來似乎並不比打開電視機費勁多少。高考填志願的時候,憑着直覺“糊里糊塗”就選擇了計算機專業。等到真正學習計算機課程的時候卻又發現,它其實很難! 

         早在2004年,還在學校的我跟很多同學一樣,喜歡看Flash,也喜歡談論Flash甚至做Flash。感覺Flash正如它的名字那樣“閃光”。那些年,在學校里,知道Flash的人可要比知道Java的人多得多,這說明當時的Flash十分火熱。此外Oracle也成為關系型數據庫里的領軍人物,很多人甚至覺得懂Oracle要比懂Flash、Java及其它數據庫要厲害得多! 

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

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

         2012年,國內又呈現出大數據熱的態勢。從國家到媒體、教育、IT等幾乎所有領域,人人都在談大數據。我的親戚朋友中,無論老師、銷售還是工程師們都可以對大數據談談自己的看法。我也找來一些Hadoop的書籍進行學習,希望能在其中探索到大數據的味道。 

         有幸在工作過程中接觸到阿里的開放數據處理服務(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的推薦;感謝張中在百忙之中給本書寫評語;感謝周亮、澄蒼、民瞻、石申、清無、少俠、征宇、三步、謝衣、曉五、法星、曦軒、九翎、峰閱、丁卯、阿末、紫丞、海炎、涵康、雲颺、孟天、零一、六仙、大知、井凡、隆君、太奇、晨炫、既望、寶升、都靈、鬼厲、歸鍾、梓撤、昊蒼、水村、惜冰、惜陌、元乾等同學在工作上的支持和幫助。

耿嘉安

北京

 

 

第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環境下搭建源碼閱讀環境時,選擇這些最常用的工具,希望能降低讀者的學習門檻,並且替大家節省時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM