1. 背景:
線上HDFS的DataNode中頻繁出現Slow write日誌
從日誌分析來看,Slow write分爲write to mirror和write to disk兩類
爲便於分析網絡或者磁盤寫入的情況,設計了HDFS的寫入監控鏈路,採集DataNode中出現的slow日誌收集,供後續分析。
2. HDFS的源碼分析
下面從源碼角度簡要分析下HDFS的block寫入流程:
如圖所示,寫入的大致流程如下:
1) DFSClient通過Sender.writeBlock方法觸發一個寫數據塊請求;
2) 該請求通過數據流管道傳送到每一個數據節點,最後一個數據節點回復請求確認,該確認消息通過數據流管道逆向送回DFSClient;
3) DFSClient收到確認消息後,將待寫入的數據切分成若干個數據包(packet),然後依次向數據流管道發送這些數據包;
4) 數據包首先到達DataNode1,寫入磁盤之後,再發送給DataNode2,依次類推;
5) 當數據包到達DataNode3時,DataNode3會對數據包進行校驗,如果校驗成功,則發送確認消息,並且逆向通過數據流管道傳回DFSClient;
6) 當所有的數據包都發送完畢之後,DFSClient會發送一個空的數據包標識當前數據快發送完畢,至此,整個數據塊流程發送完畢。
寫入過程涉及到的主要類包括:
1) DataNode啓動時會創建一個DataXceiverServer類用於監聽客戶端的讀寫請求:
在其run方法中,對於每個客戶端連接創建一個DataXceiver用於處理讀寫請求。
2) DataXceiver中寫入數據塊的邏輯在writeBlock方法中:
首先創建一個blockReceiver對象:
連接到下游節點:
調用blockReceiver的receiveBlock方法接收數據塊
3) BlockReceiver類負責接收上游的數據塊,保存到當前節點,並寫入到下游節點,核心邏輯在receiveBlock方法中:
首先讀取packet至本地緩存
寫入數據流到下一個節點:
如果接收到了完整的數據塊,並且啓動了sync標識,則寫入數據到本地磁盤
否則驗證數據包的校驗和
將數據寫入本地磁盤
3. 寫入鏈路埋點設計
DataNode中對以下四種slow情況(超過300ms)進行了warning:
1) Slow BlockReceiver write packet to mirror
2) Slow BlockReceiver write data to disk
3) Slow flushOrSync
4) Slow manageWriterOsCache
爲了追蹤記錄這4種耗時情況,在BlockReceiver類中對這四種耗時的地方打印出日誌,字段格式如下:
{
blkId: block的id
time: 時間戳
srcAddress: 當前節點地址
dstAddress: 目標節點地址
slowType: 四種slow的類型
duration: slow write的耗時
}
在BlockReceiver類中添加以下代碼打印日誌:
將日誌打印到單獨的文件中,通過filebeat收集到kafka中,再通過spark-streaming寫入到es中,打印出的日誌如下圖所示:
收集到es之後,通過相關的聚合條件可以查詢出不同slow write的耗時情況:
4. 部署方式:
將修改後的hadoop源碼重新打包,得到hadoop-hdfs-2.6.0-cdh5.5.0.jar包,替換掉hadoop路徑中的jar包。
在CDH的DataNode高級配置中的日誌記錄高級配置代碼段中添加以下配置:
log4j.appender.PACKET_TRACE=org.apache.log4j.RollingFileAppender
log4j.appender.PACKET_TRACE.Threshold=INFO
log4j.appender.PACKET_TRACE.File=${hadoop.log.dir}/packet_trace.log
log4j.appender.PACKET_TRACE.Append=true
log4j.appender.PACKET_TRACE.MaxFileSize=30MB
log4j.appender.PACKET_TRACE.MaxBackupIndex=10
log4j.appender.PACKET_TRACE.layout=org.apache.log4j.PatternLayout
log4j.logger.packet-trace = INFO, PACKET_TRACE
log4j.additivity.packet-trace = false
重啓該DataNode,則日誌信息會記錄到packet_trace.log文件中。
同時在該節點上部署filebeat,收集packet_trace.log文件的信息,寫入到kafka中。