[HDFS-inotify]“IOException:客戶端在讀取檔案後停止
1.我想寫下一個在建立時在特定位置讀取檔案的程式碼(使用inotify)
所以我在github中修改了基於“hdfs-inotify-example”的示例程式碼
https://github.com/onefoursix/ HDFS-的inotify-示例/斑點/主/ SRC /主/ JAVA / COM / onefoursix / HdfsINotifyExample.java
2.當重新命名為https://github.com/onefoursix/hdfs-inotify-example/commit/82485881c5da85a46dd1741c2d8420c7c4e81f93
case RENAME:
Event.RenameEvent renameEvent =(Event.RenameEvent)event;
配置conf = new Configuration();
conf.set(“fs.defaultFS”,defaultFS);
System.out.println(renameEvent.getDstPath()+“”+ inputPath.getPath());
if(renameEvent.getDstPath()。startsWith(inputPath.getPath())){
//嘗試讀取檔案
try(FileSystem fs = FileSystem.get(conf)){
Path filePath = new Path(defaultFS + renameEvent.getDstPath() );
BufferedReader br = new BufferedReader(new InputStreamReader(fs.open(filePath)));
字串行;
line = br.readLine();
while(line!= null){
的System.out.println(線);
line = br.readLine();
}
br.close();
}
}
它有效。但是我在檔案讀取後的下一個eventStream.take()中遇到了IOException。如果我不讀取hdfs上的檔案,就不會發生這種情況。
------------- CODE -------------
DFSInotifyEventInputStream eventStream = admin.getInotifyEventStream();
EventBatch batch = eventStream.take();
------------- LOG -------------
Cazens-MacBook-Pro:hdfs-inotify-example Cazen $ java -jar target / hdfs-inotify-example -uber.jar hdfs:// localhost:8032 / cazen / lastReadTxid
= 0
log4j:WARN找不到logger(org.apache.hadoop.util.Shell)的appender。
log4j:WARN請正確初始化log4j系統。
log4j:WARN有關詳細資訊,請參閱
TxId = 3134
事件型別= CREATE
路徑= /cazen/test2.txt._COPYING_
owner = Cazen
ctime = 1461850245559
TxId = 3138
事件型別= CLOSE
TxId = 3139
事件型別= RENAME
/cazen/test2.txt / cazen /
--------------------檔案開始
輸入檔案文字示例LOL
--------------------檔案END
異常線上程“main”中java.io.IOException:客戶端
在org.apache.hadoop.ipc.Client.call(Client.java)的org.apache.hadoop.ipc.Client.getConnection(Client.java:1507)
處停止:1451) atg.apache.hadoop.ipc.Client.call(
Client.java:1412
)
位於com.sun.proxy的org.apache.hadoop.ipc.ProtobufRpcEngine $ Invoker.invoke(ProtobufRpcEngine.java:229)。位於sun.reflect.NativeMethodAccessorImpl.invoke0 (本機方法)的
org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.getEditsFromTxid(ClientNamenodeProtocolTranslatorPB.java:1511)
上的$ Proxy9.getEditsFromTxid(未知來源)
在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)的 sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:43)
atg的java.lang.reflect.Method.invoke(Method.java:497)
。 位於com.sun.proxy的
org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102)的apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:191)
。$ Proxy10.getEditsFromTxid (未知來源)
在org.apache.hadoop.hdfs.DFSInotifyEventInputStream.poll(DFSInotifyEventInputStream.java:111)
在org.apache.hadoop.hdfs.DFSInotifyEventInputStream.take(DFSInotifyEventInputStream.java:224)
在com.onefoursix.HdfsINotifyExample.main (HdfsINotifyExample.java:40)
我可能寫錯了程式碼。如果有人已經知道這種情況,我可以問一下原因嗎?
任何意見,將不勝感激。
這看起來像是因為這會導致關閉FileSystem物件的意外副作用。Hadoop在內部快取FileSystem類的例項,並且可以將同一例項返回到多個呼叫站點。即使在一個呼叫站點關閉它之後,其他呼叫站點仍然可以保持對同一個FileSystem例項的引用。關閉FileSystem例項使其無法使用。
HdfsAdmin#getInotifyEventStream可能使用您自己的FileSystem.get呼叫返回的相同FileSystem例項。通過關閉它(使用try-with-resources),該FileSystem例項對於檢索inotify事件的後續呼叫無效。
FileSystem快取是一個相當常見的混淆源。但是,它的當前行為是設計考慮的。出於向後相容的原因,我們不能輕易改變其行為以幫助解決這類令人困惑的情況。(抱歉!)
一些嘗試的建議:
1.只是不要關閉FileSystem。即使您沒有明確地關閉它,它也會在程序拆卸時通過關閉鉤子關閉。從資源管理的角度來看,這肯定是錯誤的,但很多應用程式都是這樣工作的。
2.呼叫FileSystem#newInstance而不是FileSystem#get。newInstance方法保證返回該呼叫站點唯一的例項,而不是其他呼叫站點可能使用的共享例項。如果您使用newInstance,那麼您必須保證它已關閉以避免洩漏併產生長期影響。
3.您可以通過編輯core-site.xml並將屬性fs。<檔案系統型別> .impl.disable.cache設定為true來禁用特定檔案系統型別的FileSystem快取,例如fs.hdfs.impl.disable.cache。通常,禁用快取是不可取的,因為快取的效能優勢是顯而易見的。有時這對於特定應用程式來說是一種有用的解決方法。