參考Mac編譯Hadoop原始碼編譯好Hadoop原始碼後,就可以單步debug追原始碼了。
當然,本文不僅適用於debug Hadoop原始碼,可以無縫遷移到其他框架。
版本宣告
- 原始碼:
Apache Hadoop 2.6.0
- 系統:
macOS 10.12.4
- JDK:
oracle jdk 1.7.0_79
- IDE:
IntelliJ IDEA 2017.2.3
單執行緒debug
以單步debug追datanode原始碼為例。
啟動namenode
正常啟動namenode:
./sbin/hadoop-daemon.sh start namenode
複製程式碼
配置並啟動datanode(被除錯者)
修改etc/hadoop/hadoop-env.sh
,設定HADOOP_OPTS
:
# Extra Java runtime options. Empty by default.
HADOOP_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8888"
export HADOOP_OPTS="$HADOOP_OPTS -Djava.net.preferIPv4Stack=true"
複製程式碼
啟動datanode:
./sbin/hadoop-daemon.sh start datanode
複製程式碼
輸出:
starting datanode, logging to /Users/msh/Applications/experiment/hadoop-2.6.0/logs/hadoop-msh-datanode-mshdeMacBook-Pro.local.out
Listening for transport dt_socket at address: 8888
複製程式碼
檢視log:
tail -f /Users/msh/Applications/experiment/hadoop-2.6.0/logs/hadoop-msh-datanode-mshdeMacBook-Pro.local.logs
複製程式碼
會報檔案不存在。因為此時JVM是hang住的(等待偵錯程式連線,見下),還沒有執行main方法,也就沒有建立log檔案。
轉去配置IDEA。
配置IDEA(偵錯程式)
IDEA中開啟對應版本的hadoop原始碼(2.6.0)。
Run->Edit Configurations,左上角的+號選擇Remote,主要配置主機localhost、埠8888:
Eclipse同理。
配置項做簡單說明:
-agentlib:jdwp
:使用JDWP實現遠端除錯,包含若干子選項。transport=dt_socket
:偵錯程式和被除錯者之間使用套接字傳輸。server=y
:啟動的JVM是接收除錯請求的被除錯者(IDEA上啟動的是發出請求的偵錯程式,會存在一個server=n的程式)。suspend=y
:啟動的JVM會暫停等待,直到偵錯程式連線上才繼續執行,因此啟動datanode時才能“hang住”,等待我們啟動偵錯程式(這裡與IDEA提供的配置是suspend=n,我習慣用suspend=y)。address=8888
:被除錯者在8888埠上監聽除錯請求。
設定斷點
沿著在Datanode類的main方法設定幾個斷點:
- 演示基本的除錯互動
- 利用列印的log驗證
開始debug
偵錯程式
IDEA中,Run->Debug,選擇剛剛配置的TestDatanode引數
停在第一個斷點:
被除錯者
回到啟動datanode的終端,再次檢視log。
發現檔案已建立但是空檔案。
偵錯程式
回到IDEA,F8跳過第一個斷點,停在第二個斷點:
這句程式碼會列印啟動資訊(此處不討論)。如果執行該行後,日誌被列印,說明我們的單獨debug成功了。
F8後停在下一行,回去檢視日誌資訊。
被除錯者
檢視log:
2018-01-15 11:37:52,314 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting DataNode
...(內容太長,略)
複製程式碼
確實列印了啟動資訊。
搞定。
如果同時除錯多個節點,注意設定不同的埠
多執行緒debug
Hadoop中有大量優秀的併發設計,多執行緒debug必不可少。
IDEA設定的斷點預設只能監控前臺執行緒(一般是主執行緒),後臺執行緒遇到斷點都會忽略,無法除錯多執行緒程式碼。實際上,IDEA、Eclipse等本身支援多執行緒debug,開啟Thread模式即可。
下面仍以單步debug追datanode原始碼為例,看如何進行多執行緒debug。
開啟Thread模式
預設的斷點掛起模式為“All”:
改為Thread,並點選“Make Default”:
這樣以後設定的斷點就都是Thread模式,支援多執行緒debug了。
設定斷點
重新啟動namenode與datanode,連線上datanode。
沿著DataNode.secureMain()找到createDataNode->runDatanodeDaemon:
DataXceiver負責datanode的管道流相關操作,以守護執行緒的形式存在。以dataXceiverServer例,對應的Runable類為DataXceiverServer:
開始debug
main執行緒
執行到DataNode類中的2104行dataXceiverServer.start();
:
如果F8跳過斷點,dataXceiverServer就會在後臺啟動,繼而停在類中的133行while (datanode.shouldRun && !datanode.shutdownForUpgrade) {
。F8後,觀察目前有哪些執行緒:
注意到,底部收到一個通知:dataXceiverServer執行緒遇到了斷點。
dataXceiverServer執行緒
main執行緒放著,切換到dataXceiverServer執行緒:
圖示為“紅點+對勾”的是正常debug的執行緒,其他圖示只有“紅點”的是後臺停在斷點上的執行緒。
切換後,IDEA會自動到切換對應執行緒的虛擬機器棧:
相應自動跳到對應程式碼位置:
此時,debug操作都會作用到當前的虛擬機器棧上,即隻影響dataXceiverServer執行緒,而main執行緒保持等待(因為剛才讓main執行緒也停在了一個斷點上)。
F8,執行到accept一行,由於沒有連線發過來,dataXceiverServer執行緒會hang在這裡:
main執行緒
再切換回main執行緒。
虛擬機器棧恢復:
程式碼也還停在切換前的位置:
F8跳過2105行斷點:
main執行緒仍能夠正常debug。
有連線傳送過來的時候,dataXceiverServer執行緒會恢復RUNNING狀態,並在後臺默默執行到下一斷點,然後等待使用者切換執行緒進行debug。
搞定。
參考:
本文連結:Hadoop單步debug追原始碼
作者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議釋出,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名及連結。