1. 程式人生 > >[HDFS-inotify]“IOException:客戶端在讀取檔案後停止

[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有關詳細資訊,請參閱

http://logging.apache.org/log4j/1.2/faq.html#noconfig
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。通常,禁用快取是不可取的,因為快取的效能優勢是顯而易見的。有時這對於特定應用程式來說是一種有用的解決方法。