關於想瞭解HDFS的源碼的朋友, 可以到蔡斌大哥那讀讀他的javaeye.
很抱歉, 我用了神秘殺手一詞, 因為它實在害我太慘, 又花了好大精力才把它給拎出來。
近來在測試Hadoop時, 使用NameNode身上的dfshealth.jsp 管理頁面發現,DataNode在啟動並執行過程中, Last Contact 參數時常會超過3。LC(Last Contact)的意思是表明DataNode有多少秒的時間未向NameNode發送心跳包了. 然而預設DataNode是3秒發送一次, 我們都知道,NameNode預設以10分鐘作為DN的死亡逾時時間,那麼究竟有哪些因素會導致JSP管理頁面LC參數超過3,甚至會達到200以上,這樣的情況對我們的系統的穩定運行究竟有沒有影響?
事實上,這現象我觀察了好一陣子,影響LC參數增大的原因有下面幾種情況:
1. HDFS收到大量刪除BLOCK的命令. 請參見:https://issues.apache.org/jira/browse/HDFS-611;
2. HDFS 有大量BLOCK需要report 給NN;
3. 組織心跳包的資料;
4. 網路環境。
前兩種情況LC的值一般不會超過100,對效能不會造成很大影響。 Hadoop-0.22.0 以後版本,Hadoop也有所改進。
那麼值的一提的是DN在組織心跳包期間,對FSDatasetInterface 介面進行了相關方法的調用,具體可以參考一下FSDatasetMBean介面中的幾個方法: Java代碼
- /**
- * Returns the total space (in bytes) used by dfs datanode
- * @return the total space used by dfs datanode
- * @throws IOException
- */
- public long getDfsUsed() throws IOException;
-
- /**
- * Returns total capacity (in bytes) of storage (used and unused)
- * @return total capacity of storage (used and unused)
- * @throws IOException
- */
- public long getCapacity() throws IOException;
-
- /**
- * Returns the amount of free storage space (in bytes)
- * @return The amount of free storage space
- * @throws IOException
- */
- public long getRemaining() throws IOException;
這三個方法意思大家都很明白,它們的實現者分別為DF,DU兩個類,它們會不週期性通過Shell類的runComamnd方法來執行系統命令,以擷取目前的目錄的 df, du 值。
然而在執行的過程當中有趣的事情發生了,筆者有13個分區,一共存有14萬多個BLOCK,
Df 和du 平均每次執行的時間都會超過兩秒,戲劇性的是DU 和DF最高的一次在執行某分區目錄的命令時,居然用了180秒以上。(Shell#runCommand方法中, 從ProcessBuilder 執行個體化到process.start() 執行時間)。
難道是分區目錄下的BLOCK數量過多導致運行緩慢麼,在linux 系統裡執行DF DU相同的命令結果都是以毫秒時間結束。那問題顯然出在了ProcessBuilder, 居瞭解,該類由JVM通過Linux 核心來fork 子進程,子進程當然會完全繼承父進程的所有記憶體控制代碼,jstack看到JVM此時線程狀態大部分處於WAITING, 這個過程經過測試確實會影響DFSClient寫入逾時,或關閉流出錯(下篇會說到, 作為長久Running 的DFSClient, 應該做好流的關閉工作,0.21-trunk中流的關閉仍然存有安全隱患。) 最後我折騰過從32位機子一路換到64位的機子,但問題依然存在。
最後只好再次對HDFS開刀,重構了DU,DF 以及自己的IOStat , Uptime類,通過Linux系統來執行,把結果輸出到臨時檔案中,然後由Hadoop來讀取。 LC的問題不再發生。 當然有朋友遇到過,並且有解決方案的可以聯絡我 dongtalk@gmail.com .