博客地址:joey771.cn/2018/10/26/…java
咱們在寫Spark程序的時候免不了要對咱們的代碼進行debug,在代碼當中打上斷點來查看程序執行過程當中各個變量的變化狀況。我通常使用Intellij IDEA來寫Spark程序,能夠直接在其中以local的方式運行Spark程序,也能夠在其中打上斷點進行調試,但這樣作有一些問題:程序員
以前所說的幾點問題我在以前通常採用比較低效率的方式來進行debug,即在代碼當中加入一些log信息,利用log信息來調試代碼,這樣當Spark程序在集羣中運行時,能夠在web UI的Executor的stdout和stderr中查看咱們留下的log信息。這樣作能夠解決一些問題,可是十分低效,debug的信息須要添加改動時都須要從新編譯程序,而且打印log信息的方式並不能很完整地觀察到全部變量的變化狀況。但這樣作確實解決了一些問題,好比咱們能夠對Executor真正執行Task邏輯的代碼進行調試,也無需考慮惰性執行的過程,Spark的全部RDD的transform的行爲都會反映到每一個Executor執行的stdout和stderr信息當中;這些代碼均可以在服務器集羣當中運行進行調試,不用擔憂本地電腦性能不夠的問題,本地電腦只須要打開瀏覽器查看Spark的web UI便可,或者使用終端來查看一些信息;能夠在集羣當中調試代碼,不須要侷限於local模式下。web
但我始終認爲這樣的debug方式是低效的,而且不是一個正常的程序員應該有的debug方式,以前有想過確定有具體的方法來解決這樣的調試問題,Intellij IDEA當中功能很是多,確定有這樣的功能來解決這個問題。近期又要寫一些Spark程序,而且輸入數據很是大,計算量也很大,我在本地電腦上根本沒辦法debug,因而想到了去查找一些資料來解決遠程調試Spark程序的問題。其實Intellij IDEA或者Eclipse這樣的IED都會有remote debug這樣的功能,以Intellij IDEA爲例,在Run-Edit Configurations菜單中咱們能夠添加一個Remote的Configurations,這就是Intellij IDEA爲咱們提供的遠程調試的功能。這裏對Spark程序的調試主要分兩種——Driver程序調試和Executor程序調試。apache
Driver程序在遠程進行調試時,須要在spark-submit的參數中增長一個配置:瀏覽器
--conf spark.driver.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
複製代碼
或bash
--driver-java-options -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
複製代碼
咱們隊這個參數進行一些說明,首先spark.driver.exetraJavaOptions這個參數容許咱們在Spark的driver程序在運行時傳入一些額外的Java參數,agentlib:jdwp
是Java Debug Wire Protocol選項,是一個遠程調試的協議,後面緊跟的是以逗號進行分隔的子選項:服務器
transport
定義了遠程Debugger及Debuggee之間數據傳輸協議,能夠選擇socket和shared memory的方式,通常狀況下都是選擇socket的方式,即選項的值選擇dt_socketserver
運行Java程序的進程是否做爲服務端與客戶端(Debugger)進行通訊,一般狀況下遠程調試都須要有一個服務端和一個客戶端,若運行Java程序端爲服務端,則調試端爲客戶端,在調試driver程序時,選擇Java程序爲服務端,監聽遠端Debugger的鏈接,所以值爲y(yes)suspend
是否暫停執行直至有客戶端(Debugger)成功鏈接到服務端,調試driver程序時將這個值設置爲y(yes)使得driver程序會在剛啓動時就暫停住,指到有遠端Debugger客戶端鏈接上來才繼續執行,確保遠端Debugger能在程序開始執行時已經鏈接完畢address
監聽的端口,即服務端socket監聽的端口,能夠設置爲任意可用的沒有被佔用的端口號,只要確保客戶端可以經過這個端口與服務端進行鏈接便可進行了如上設置以後,在咱們容許spark-submit指令以後,咱們通常可以看到Spark程序暫停住了,而且會顯示以下這樣一句話:app
Listening for transport dt_socket at address: 5005
複製代碼
這時候,咱們的Spark程序已經作好準備在等待遠程Debugger客戶端鏈接了(通常稱之爲attach),接下來就在Intellij IDEA中打開以前所說的那個菜單,點擊「+」添加一個新的run/debug configuration,這裏選擇的是Remote類型,Debugger mode選擇Attach to remote JVM,接下來填入Host和port並選擇moudle classpath,以後使用這個配置點擊debug按鈕即可以進行遠程調試了。socket
通常來講,咱們進行Spark程序調試最主要的就是要對Task當中的執行邏輯進行調試,由於Executor中執行的纔是真正的並行任務,也是程序最主要的部分。對Executor進行調試時咱們通常將容許Java進程的服務器做爲客戶端,將Debugger所在的機器做爲服務端,也就是在調試機器上啓動一個socket服務器對指定端口進行監聽,而Executor上運行的程序做爲客戶端與之進行鏈接。爲何不採用以前的那種模式呢?由於咱們須要保證Executor上的程序一開始執行就與Debugger進行了鏈接,若採用以前的模式,就須要將Executor進行暫停,而Executor暫停會使得driver程序誤認爲其出現了故障,會不斷的重啓Executor,沒法正常進行調試。通常狀況下要這樣進行調試須要將Executor設置爲只有一個,由於多個Executor同時鏈接Debugger的服務端會出現問題,若必定要進行集羣調試,則在指定Worker啓動的時候加入參數,而不是在spark-submit的時候加入參數,首先說下參數:性能
--conf spark.executor.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=n,address=10.0.0.171:5005,suspend=n
複製代碼
參數的具體意思不用多加說明,主要是address這裏要寫入具體的Debugger的地址以及端口號,若是要指定一個Worker上啓動一個Executor來進行調試,能夠在使用手動的方式啓動該Worker
spark-class -agentlib:jdwp=transport=dt_socket,server=n,address=10.0.0.171:5005,suspend=n org.apache.spark.deploy.worker.Worker spark://10.0.0.1:7077
複製代碼
只要給該Worker分配必定的資源,確保在這個Worker上啓動一個Executor便可。Intellij IDEA的設置上和以前的區別就是將Debugger mode改成Listen to remote JVM,而後首先須要啓動Debugger的服務端,即先在Intellij IDEA當中點擊debug開啓服務,再運行Spark程序,這樣遠端的Spark Executor上運行的程序會自動進行鏈接,方便進行debug。這裏須要注意的是,debug過程當中不要讓一行代碼停留太長時間,不然driver會認爲該Executor出現了故障,會不斷進行重啓Executor。
參考資料: