HDFS二次开发常见问题

原文链接: https://forum.huawei.com/enterprise/zh/thread-471255.html

HDFS二次开发常见问题


问题描述


客户开发了一个HDFS应用,此应用存在多个线程,需同时往HDFS组件上写数据。在业务运行时,发现有业务线程和HDFS交互时,报如下异常:

......
Exception in thread "main" java.io.IOException: Filesystem closed
at org.apache.hadoop.hdfs.DFSClient.checkOpen(DFSClient.java:498)
at org.apache.hadoop.hdfs.DFSClient.getFileInfo(DFSClient.java:1869)
at
org.apache.hadoop.hdfs.DistributedFileSystem$26.doCall(DistributedFileSystem.java:1474)
at
org.apache.hadoop.hdfs.DistributedFileSystem$26.doCall(DistributedFileSystem.java:1470)
at org.apache.hadoop.fs.FileSystemLinkResolver.resolve(FileSystemLinkResolver.java:81)
at
org.apache.hadoop.hdfs.DistributedFileSystem.getFileStatus(DistributedFileSystem.java:1
470)
at org.apache.hadoop.fs.FileSystem.exists(FileSystem.java:1444)
......

原因分析

经分析,捕捉到异常的业务应用线程确实有建立到HDFS组件连接,并且这个过程中此业务应用线程并没close这个连接实例,连接初始化API示意代码:

FileSystem hdfs1 = FileSystem.get(conf);

再排查此业务应用代码,发现在其他线程中有close连接实例的操作,关闭连接实例的API示意代码:

hdfs1.close();

深入分析发现:多个线程通过HDFS提供API申请并获取到HDFS连接实例,但实际上是同一个连接实例,所以在同一个业务进程内,一旦一个线程close一个HDFS连接实例,其他线程即无法再使用先前所申请的连接实例。

如下是对这个问题的演示DEMO:

......
FileSystem hdfs1 = FileSystem.get(conf);
FileSystem hdfs2 = FileSystem.get(conf);
System.out.println("/user/tester1/spark-core is "
+ hdfs1.exists(new Path("/user/tester1/spark-core")));
System.out.println("/user/tester1/hive-date is "
+ hdfs2.exists(new Path("/user/tester1/hive-date")));
hdfs1.close();
System.out.println("/user/tester1/hive-date is "
+ hdfs2.exists(new Path("/user/tester1/hive-date"))); // 这里会失败,因为上面已经把连
接实例关闭了。

解决办法


属于HDFS机制,并不是bug。业务应用需根据自己的实际业务场景来确定如何使用HDFS连接。一般建议如下,供参考:

  1. 业务进程空间中,统一建立和管理(例如close)一个连接实例,各个线程共用,但不要直接管理此连接实例;

  2. 若实在有必要给一个线程单独分配一个连接实例,可以按照HDFS机制,在创建连接实例时,指定不采用缓存中的连接实例,具体API的使用DEMO如下:

      c. ......
      d. FileSystem hdfs1 = FileSystem.get(conf);
      e. conf.setBoolean("fs.hdfs.impl.disable.cache", true);//指定不采用缓存中的连接实例
      f. FileSystem hdfs2 = FileSystem.get(conf);
      g.
      h. System.out.println("/user/tester1/spark-core is "
      i. + hdfs1.exists(new Path("/user/tester1/spark-core")));
      j. System.out.println("/user/tester1/hive-date is "
      k. + hdfs2.exists(new Path("/user/tester1/hive-date")));
      l.
      m. hdfs1.close();
      n. System.out.println("/user/tester1/hive-date is "
      + hdfs2.exists(new Path("/user/tester1/hive-date"))); // 这里不会再抛出问题描述中的异
      常。

转载自:

https://forum.huawei.com/enterprise/zh/thread-471255.html

猜你喜欢

转载自blog.csdn.net/qq_41946557/article/details/102756110
今日推荐