原創文章,謝絕轉載html
筆者出於工做及學習的目的,常常與Spark源碼打交道,也不免對Spark源碼作修改及測試。本人一貫講究藉助工具提高效率,開發Spark過程當中也在摸索如何更加順暢的對源碼進行調試。java
Spark基於Scala,採用IntelliJ IDEA和sbt應對平常開發,天然是最佳選擇了。如何導入及編譯Spark項目,網上資料不少,官網給的教程也比較詳細:git
本文基於Spark2.x的源碼,重點介紹如何使用sbt結合IDEA對Spark進行斷點調試開發,這對於常常修改或學習Spark源碼的讀者較爲有益。廢話到此,咱們進入正題。github
首次拿到Spark源碼,直接導入IDEA會有不少錯誤,由於SQL項目的catalyst中的SQL語法解析依賴ANTLR語法定義,須要經過編譯生成代碼,以下是採用sbt打包編譯的流程:sql
git clone https://github.com/apache/spark.git cd spark build/sbt package
...通過漫長等待,成功編譯後,導入IDEA就能夠正常看源碼了。apache
你們能夠採用阿里雲的Maven倉庫,加速下包的過程,能夠參考個人這篇文章:https://zhuanlan.zhihu.com/p/25279570jvm
我習慣於直接在Spark項目中寫TestCase的方式做爲執行Spark的入口,這種方式對於常常修改Spark源碼的開發場景很適用,相比在SparkShell中寫測試代碼有如下好處:socket
Spark源碼自帶大量的TestCase可供咱們學習參考,咱們以Spark的SQL項目爲例,將spark/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala
複製爲SimpleSuite.scala
。ide
注意,這裏不要是使用IDEA自帶的複製功能,由於IDEA在複製的時候會從新組織代碼中import的次序,這有可能會致使編譯出錯。正確的姿式應該是:工具
cp xxx xxx2
完成複製咱們之因此要基於SQLQuerySuite
複製出一個SimpleSuite
文件是由於:Spark爲了確保代碼風格一致規範(好比每一個代碼文件頭部須要定義Apache的License註釋;import的順序爲java,scala,3rdParty,spark),在項目引入了Scala-style checker,若是代碼不合規範,執行編譯會出錯。直接複製一個文件在上面作修改能夠避免踩到代碼風格檢查的坑。我將SimpleSuite的內容修改以下:
打開IDEA的Terminal窗口,執行build/sbt進入sbt的交互式環境,經過如下方式執行咱們的SimpleSuite:
> project sql > testOnly *SimpleSuite
project sql
指的是切換到SQL項目,這樣在執行testOnly時能夠快速定位到咱們的SimpleSuite類,能夠執行projects
查看Spark定義的全部子模塊,當前所在的模塊名稱前會有個*
的標識。首次執行測試的時間比較長,再次執行就會比較快了,若是測試經過的話,會看到以下信息:
在sbt中執行exit
退出交互式環境,接下來介紹如何使用sbt結合IDEA進行斷點調試。
因爲sbt是在Terminal中單獨啓動的進程,要對sbt調試,就須要採用IDEA的遠程調試功能了。在IDAE的菜單中選擇Run -> Edit Configrations...
,在接下來的窗口中添加一個Remote配置:
配置名稱你們隨意,我這裏爲Spark,遠程調試的端口爲5005,若是本地的5005端口被佔用,改成其餘端口便可。
而後回到Terminal從新啓動sbt,啓動時須要添加遠程調試參數:build/sbt -jvm-debug 5005
,啓動過程當中會提示Listening for transport dt_socket at address: 5005
,啓動sbt後,咱們就能夠經過IDEA對sbt進行調試了。
接下來咱們給SimpleSuite的test方法內部隨意添加一個斷點,回到sbt執行:
> project sql > set fork in Test := false > testOnly *SimpleSuite
一切順利的話,執行testOnly的過程當中,咱們的斷點會被命中:
若是對Spark源碼或SimpleSuite的代碼作了修改只須要從新執行testOnly *SimpleSuite
便可。
讓IDEA命中斷點有一個關鍵的語句:set fork in Test := false
,這個語句的做用是讓sbt執行Test時避免fork子進程。咱們啓動sbt的時候添加的遠程調試端口是加在sbt上的,若是執行Test不在一個進程內,IDEA就沒法命中斷點。
若是頻繁修改代碼,反覆執行testOnly
不免有些不便,咱們能夠採用sbt的持續編譯功能簡化流程。執行時加上~
,也就是~testOnly *SimpleSuite
,這樣,咱們修改代碼,在保存,sbt會監控文件變化並自動執行測試,超級方便。這種方式一樣適用於compile,test,run等命令。
幾個關鍵點:
# Spark源碼目錄下執行(以SimpleSuite爲例): $ build/sbt -jvm-debug 5005 > project sql > set fork in Test := false > testOnly *SimpleSuite
OK,掌握以上技巧,咱們就能夠愉快的深刻Spark源碼內部,瞭解Spark的運做機制了。