sbt結合IDEA對Spark進行斷點調試開發

原創文章,謝絕轉載html

筆者出於工做及學習的目的,常常與Spark源碼打交道,也不免對Spark源碼作修改及測試。本人一貫講究藉助工具提高效率,開發Spark過程當中也在摸索如何更加順暢的對源碼進行調試。java

Spark基於Scala,採用IntelliJ IDEA和sbt應對平常開發,天然是最佳選擇了。如何導入及編譯Spark項目,網上資料不少,官網給的教程也比較詳細:git

本文基於Spark2.x的源碼,重點介紹如何使用sbt結合IDEA對Spark進行斷點調試開發,這對於常常修改或學習Spark源碼的讀者較爲有益。廢話到此,咱們進入正題。github

Spark源碼編譯

首次拿到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

  • 代碼保留在文件中,方便修改從新執行
  • 代碼在同一個項目中,源碼修改後IDEA無需對代碼進行二次索引
  • 方便進行持續測試(Continuous Test)

Spark源碼自帶大量的TestCase可供咱們學習參考,咱們以Spark的SQL項目爲例,將spark/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala複製爲SimpleSuite.scalaide

注意,這裏不要是使用IDEA自帶的複製功能,由於IDEA在複製的時候會從新組織代碼中import的次序,這有可能會致使編譯出錯。正確的姿式應該是:工具

  1. 在IDEA中,找到要複製的文件,右擊,複製代碼路徑

  1. 在IDEA的Terminal窗口中執行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結合IDEA對Spark進行斷點調試

因爲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的運做機制了。

相關文章
相關標籤/搜索