Hadoop單步debug追原始碼

monkeysayhi發表於2018-01-25

參考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:

image.png

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方法設定幾個斷點:

  • 演示基本的除錯互動

image.png

  • 利用列印的log驗證

image.png

開始debug

偵錯程式

IDEA中,Run->Debug,選擇剛剛配置的TestDatanode引數

image.png

停在第一個斷點:

image.png

被除錯者

回到啟動datanode的終端,再次檢視log。

發現檔案已建立但是空檔案。

偵錯程式

回到IDEA,F8跳過第一個斷點,停在第二個斷點:

image.png

這句程式碼會列印啟動資訊(此處不討論)。如果執行該行後,日誌被列印,說明我們的單獨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”:

image.png

改為Thread,並點選“Make Default”:

image.png

這樣以後設定的斷點就都是Thread模式,支援多執行緒debug了。

設定斷點

重新啟動namenode與datanode,連線上datanode。

沿著DataNode.secureMain()找到createDataNode->runDatanodeDaemon:

image.png

DataXceiver負責datanode的管道流相關操作,以守護執行緒的形式存在。以dataXceiverServer例,對應的Runable類為DataXceiverServer:

image.png

開始debug

main執行緒

執行到DataNode類中的2104行dataXceiverServer.start();

image.png

如果F8跳過斷點,dataXceiverServer就會在後臺啟動,繼而停在類中的133行while (datanode.shouldRun && !datanode.shutdownForUpgrade) {。F8後,觀察目前有哪些執行緒:

image.png

注意到,底部收到一個通知:dataXceiverServer執行緒遇到了斷點。

dataXceiverServer執行緒

main執行緒放著,切換到dataXceiverServer執行緒:

image.png

圖示為“紅點+對勾”的是正常debug的執行緒,其他圖示只有“紅點”的是後臺停在斷點上的執行緒。

切換後,IDEA會自動到切換對應執行緒的虛擬機器棧:

image.png

相應自動跳到對應程式碼位置:

image.png

此時,debug操作都會作用到當前的虛擬機器棧上,即隻影響dataXceiverServer執行緒,而main執行緒保持等待(因為剛才讓main執行緒也停在了一個斷點上)。

F8,執行到accept一行,由於沒有連線發過來,dataXceiverServer執行緒會hang在這裡:

image.png

main執行緒

再切換回main執行緒。

虛擬機器棧恢復:

image.png

程式碼也還停在切換前的位置:

image.png

F8跳過2105行斷點:

image.png

main執行緒仍能夠正常debug。

有連線傳送過來的時候,dataXceiverServer執行緒會恢復RUNNING狀態,並在後臺默默執行到下一斷點,然後等待使用者切換執行緒進行debug。

搞定。


參考:


本文連結:Hadoop單步debug追原始碼
作者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議釋出,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名及連結。

相關文章