Java HDFS API 追加檔案寫入內容異常問題的解決

appleyk發表於2018-06-28



最近在完善一個Java HDFS 的Api功能類,其功能列表如下(主要利用檔案系統進行檔案或目錄的各種操作):






上述功能有:

1、獲取當前HDFS系統的狀態,如容量多少,使用了多少,剩餘多少(getStatus())

2、開啟一個檔案,並返回開啟後的FS資料的輸出流,便於向檔案裡編寫內容(open(destPath))

3、上傳本地(local或remote)檔案至HDFS檔案系統(upLoadFile(srcPath,destPath,dealSrc,override))

4、檔案或目錄的重新命名(rename(srcPath,destPath))

5、驗證HDFS的回收站功能是否開啟(trashEnabled()) ....etc






上述功能有:


1、拿到檔案系統的回收站路徑(getTrashDirPath())

2、將檔案或目錄移除(搬家)到回收站(開啟Hadoop回收站功能,並設定檔案的回收週期和檢查點,可參考我的上一篇文章

3、將回收站中指定的檔案或目錄進行還原(恢復,restoreFromTrash(srcPath,destPath)) 

4、清空回收站(emptyTrash())

5、開啟已存在的檔案,並進行檔案內容的追加(appendStringToFile(srcPath,content)) ....etc



在進行檔案追加內容的demo測試時,報了一段異常,以追加檔案1.txt為例







測試demo如下:



	/**
	 * 追加檔案,新增內容
	 */
	@Test
	public void appendFile() throws Exception {
		initApi();
		api.appendStringToFile("1.txt", "2018年6月28日17:49:50");
		api.close();
	}
	


執行後,報異常如下:


java.io.IOException: Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try. (Nodes: current=[DatanodeInfoWithStorage[192.168.142.142:9866,DS-739b593f-ef79-4b6f-9e88-99761faf4064,DISK], DatanodeInfoWithStorage[192.168.142.143:9866,DS-be84ef18-1fb3-4859-adee-85eef093ac02,DISK]], original=[DatanodeInfoWithStorage[192.168.142.142:9866,DS-739b593f-ef79-4b6f-9e88-99761faf4064,DISK], DatanodeInfoWithStorage[192.168.142.143:9866,DS-be84ef18-1fb3-4859-adee-85eef093ac02,DISK]]). The current failed datanode replacement policy is DEFAULT, and a client may configure this via 'dfs.client.block.write.replace-datanode-on-failure.policy' in its configuration.
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.findNewDatanode(DFSOutputStream.java:929)
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.addDatanode2ExistingPipeline(DFSOutputStream.java:984)
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.setupPipelineForAppendOrRecovery(DFSOutputStream.java:1131)
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:455)


Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try.

異常意思大概是:由於可用的DataNode不多了,導致當前管道中壞掉的DataNode無法被替換


直接貼出解決方案,在Client端,設定conf的properties如下:



Configuration conf = new Configuration();
	
/**
 * dfs.client.block.write.replace-datanode-on-failure.enable=true
 * 如果在寫入管道中存在一個DataNode或者網路故障時,
 * 那麼DFSClient將嘗試從管道中刪除失敗的DataNode,
 * 然後繼續嘗試剩下的DataNodes進行寫入。
 * 結果,管道中的DataNodes的數量在減少。
 * enable :啟用特性,disable:禁用特性
 * 該特性是在管道中新增新的DataNodes。
 * 當叢集規模非常小時,例如3個節點或更少時,叢集管理員可能希望將策略在預設配置檔案裡面設定為NEVER或者禁用該特性。
 * 否則,因為找不到新的DataNode來替換,使用者可能會經歷異常高的管道寫入錯誤,導致追加檔案操作失敗
 */
conf.set("dfs.client.block.write.replace-datanode-on-failure.enable", "true");

/**
 * dfs.client.block.write.replace-datanode-on-failure.policy=DEFAULT
 * 這個屬性只有在dfs.client.block.write.replace-datanode-on-failure.enable設定true時有效:
 * ALWAYS :當一個存在的DataNode被刪除時,總是新增一個新的DataNode
 * NEVER  :永遠不新增新的DataNode
 * DEFAULT:副本數是r,DataNode的數時n,只要r >= 3時,或者floor(r/2)大於等於n時
 * r>n時再新增一個新的DataNode,並且這個塊是hflushed/appended
 */
conf.set("dfs.client.block.write.replace-datanode-on-failure.policy", "NEVER");


   看來叢集小了,也是事啊(我本地測試環境,只有兩個DataNode,索性直接啟動該特性,失敗的時候新增新的DataNode)


    在執行一次demo,這次無異常丟擲







我們下載1.txt到本地,並檢視內容如下:








相關文章