[解決]java.io.IOException: Cannot obtain block length for LocatedBlock
原文:
https://blog.csdn.net/odailidong/article/details/51420701
https://www.cnblogs.com/cssdongl/p/6700512.html
轉載請註明原文出處
博文-1:
在hadoop測試叢集執行job的過程中發現部分執行失敗,有Cannot obtain block length for LocatedBlock,使用hdfs dfs -cat ${檔案}的時候也報這個錯,看過程式碼後發現是檔案未被正常關閉(flume傳到hdfs上的,可能由於Namenode長時間gc或者切換或者重啟會留下很多.tmp結尾的檔案),為此,使用hadoop命令顯示處於開啟狀態的檔案,然後刪除這些檔案:
hadoop fsck / -openforwrite | egrep -v ‘^.+ //” | xargs -i hadoop fs -rmr {};
然後重傳這些檔案到hdfs。
這幾天想cat一下某天的HDFS檔案內容的時候突然報Cannot obtain block length for LocatedBlock異常,get也一樣,這樣無法訪問hdfs檔案的問題必須解決,Mark一下問題背景和解決過程
博文-2:
一.問題背景
問題產生的原因可能是由於前幾日Hadoop叢集維護的時候,基礎運維組操作不當,先關閉的Hadoop叢集,然後才關閉的Flume agent導致的hdfs檔案寫入後狀態不一致。排查和解決過程如下.
二.解決過程
1.既然是hdfs檔案出問題,用fsck檢查一下吧
hdfs fsck /
當然你可以具體到指定的hdfs路徑,檢查完列印結果沒有發現任何異常,沒有發現損壞或者Corrupt的block,繼續排查
2.那麼加上其他引數細查
hdfs fsck / –openforwrite
ok,這次檢查出來不少檔案列印顯示都是 openforwrite狀態,而且我測試相應檔案確實不能讀取,這很不正常不是嗎?Flume已經寫過的hdfs檔案居然還處於openforwrite狀態,而且無法cat和get
所以這裡的”Cannot obtain block length for LocatedBlock”結合字面意思講應該是當前有檔案處於寫入狀態尚未關閉,無法與對應的datanode通訊來成功標識其block長度.
那麼分析其產生的可能性,舉栗子如下
1>Flume客戶端寫入hdfs檔案時的網路連線被不正常的關閉了
或者
2>Flume客戶端寫入hdfs失敗了,而且其replication副本也丟失了
我這裡應該屬於第一種,總結一下就是Flume寫入的hdfs檔案由於什麼原因沒有被正常close,狀態不一致隨後無法正常訪問.繼續排查
3.推斷:HDFS檔案租約未釋放
可以參考這篇文章來了解HDFS租約機制 http://www.cnblogs.com/cssdongl/p/6699919.html
瞭解過HDFS租約後我們知道,客戶端在每次讀寫HDFS檔案的時候獲取租約對檔案進行讀寫,檔案讀取完畢了,然後再釋放此租約.檔案狀態就是關閉的了。
但是結合當前場景由於先關閉的hadoop叢集,後關閉的Flume sink hdfs,那麼hadoop叢集都關了,Flume還在對hdfs檔案寫入,那麼租約最後釋放了嗎?答案是肯定沒釋放.
4.恢復租約
對於這些狀態損壞的檔案來講,rm掉的話是很暴力的做法,萬一上游對應日期的資料已經沒有rention呢?所以,既然沒有釋放租約,那麼恢復租約close掉檔案就是了,如下命令
hdfs debug recoverLease -path -retries
請將修改成你需要恢復的租約狀態不一致的hdfs檔案的具體路徑,如果要恢復的很多,可以寫個自動化指令碼來找出需要恢復的所有檔案然後統一恢復租約.
ok,執行完命令後再次cat對應hdfs檔案已無異常,順利顯示內容,問題解決.