首页 文章

使用Java读取远程HDFS文件

提问于
浏览
6

我在使用简单的Hadoop安装时遇到了一些麻烦 . 我已经下载了hadoop 2.4.0并安装在一个CentOS Linux节点(虚拟机)上 . 我已经为apache站点(http://hadoop.apache.org/docs/r2.4.0/hadoop-project-dist/hadoop-common/SingleCluster.html)上描述的具有伪分发的单个节点配置了hadoop . 它从日志中没有问题开始,我可以使用命令行中的“hadoop fs”命令读取写入文件 .

我正在尝试使用Java API从远程计算机上的HDFS读取文件 . 机器可以连接并列出目录内容 . 它还可以确定文件是否存在以及代码:

Path p=new Path("hdfs://test.server:9000/usr/test/test_file.txt");
FileSystem fs = FileSystem.get(new Configuration());
System.out.println(p.getName() + " exists: " + fs.exists(p));

系统打印“true”表示它存在 . 但是,当我尝试使用以下内容读取文件时:

BufferedReader br = null;
try {
    Path p=new Path("hdfs://test.server:9000/usr/test/test_file.txt");
    FileSystem fs = FileSystem.get(CONFIG);
    System.out.println(p.getName() + " exists: " + fs.exists(p));

    br=new BufferedReader(new InputStreamReader(fs.open(p)));
    String line = br.readLine();

    while (line != null) {
        System.out.println(line);
        line=br.readLine();
    }
}
finally {
    if(br != null) br.close();
}

此代码抛出异常:

Exception in thread "main" org.apache.hadoop.hdfs.BlockMissingException: Could not obtain block: BP-13917963-127.0.0.1-1398476189167:blk_1073741831_1007 file=/usr/test/test_file.txt

谷歌搜索提供了一些可能的提示,但都检查了 . 数据节点已连接,处于活动状态,并且具有足够的空间 . 来自hdfs dfsadmin -report的管理员报告显示:

已配置容量:52844687360(49.22 GB)当前容量:48507940864(45.18 GB)DFS剩余:48507887616(45.18 GB)使用DFS:53248(52 KB)DFS已使用%:0.00%在复制块下:0块具有损坏的副本:0缺少块:0可用的数据节点:1(总共1个,0个死)实时数据节点:名称:127.0.0.1:50010(test.server)主机名:test.server停用状态:正常配置容量:52844687360(49.22 GB)使用的DFS: 53248(52 KB)非DFS使用:4336746496(4.04 GB)DFS剩余:48507887616(45.18 GB)DFS使用%:0.00%DFS剩余%:91.79%配置缓存容量:0(0 B)使用的缓存:0(0 B )剩余高速缓存:0(0 B)使用的高速缓存%:100.00%高速缓存剩余%:0.00%最后联系人:Fri Apr 25 22:16:56 PDT 2014

客户端jar直接从hadoop安装中复制,因此没有版本不匹配 . 我可以使用Java类浏览文件系统并读取文件属性 . 我没有得到异常就无法读取文件内容 . 如果我尝试用代码编写一个文件:

FileSystem fs = null;
BufferedWriter br = null;

System.setProperty("HADOOP_USER_NAME", "root");

try {
    fs = FileSystem.get(new Configuraion());

    //Path p = new Path(dir, file);
    Path p = new Path("hdfs://test.server:9000/usr/test/test.txt");
    br = new BufferedWriter(new OutputStreamWriter(fs.create(p,true)));
    br.write("Hello World");
}
finally {
    if(br != null) br.close();
    if(fs != null) fs.close();
}

这会创建文件但不会写任何字节并抛出异常:

Exception in thread "main" org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /usr/test/test.txt could only be replicated to 0 nodes instead of minReplication (=1). There are 1 datanode(s) running and 1 node(s) are excluded in this operation.

谷歌搜索表明可能的空间问题,但从dfsadmin报告,似乎有足够的空间 . 这是一个简单的vanilla安装,我无法解决这个问题 .

环境摘要是:

服务器:

带有伪分发的Hadoop 2.4.0(http://hadoop.apache.org/docs/r2.4.0/hadoop-project-dist/hadoop-common/SingleCluster.html

CentOS 6.5虚拟机64位服务器Java 1.7.0_55

客户:

Windows 8(虚拟机)Java 1.7.0_51

任何帮助是极大的赞赏 .

3 回答

  • 2

    Hadoop错误消息令人沮丧 . 他们常常不说出他们的意思,与真正的问题无关 . 我发现当客户端,namenode和datanode无法正常通信时会发生这样的问题 . 在你的情况下,我会选择以下两个问题之一:

    • 您的群集在VM中运行,并且其对客户端的虚拟化网络访问被阻止 .

    • 您并未始终如一地使用在客户端和主机之间以相同方式解析的完全限定域名(FQDN) .

    主机名“test.server”非常可疑 . 检查以下所有内容:

    • test.server是FQDN吗?

    • 这是在conf文件中随处使用的名称吗?

    • 客户端和所有主机是否可以正向和反向解析"test.server"及其IP地址并获得相同的功能?

    • 是否在任何地方使用IP地址而不是FQDN?

    • "localhost"被用在哪里?

    必须删除使用FQDN,主机名,数字IP和localhost的任何不一致 . 不要在conf文件或客户端代码中混用它们 . 一致使用FQDN是优选的 . 一致使用数字IP通常也有效 . 使用非限定主机名,localhost或127.0.0.1会导致问题 .

  • 1

    上面的答案指向了正确的方向 . 请允许我添加以下内容:

    • Namenode不直接读取或写入数据 .

    • 客户端(使用直接访问HDFS的Java程序)与Namenode交互以更新HDFS命名空间并检索用于读/写的块位置 .

    • 客户端直接与Datanode交互以读/写数据 .

    您可以列出目录内容,因为您的客户端代码可以访问 hostname:9000 . 你正在做上面的数字2 .
    为了能够读写,您的客户端代码需要访问Datanode(编号3) . Datanode DFS数据传输的默认端口是50010.有些东西阻止了客户端与 hostname:50010 的通信 . 可能是防火墙或SSH隧道配置问题 .
    我使用的是Hadoop 2.7.2,所以也许你有一个不同的端口号设置 .

  • 1

    我们需要确保使用fs.default.name空间集进行配置,例如

    configuration.set("fs.default.name","hdfs://ourHDFSNameNode:50000");

    下面我放了一段示例代码:

    Configuration configuration = new Configuration();
     configuration.set("fs.default.name","hdfs://ourHDFSNameNode:50000");
     FileSystem fs = pt.getFileSystem(configuration);
     BufferedReader br = new BufferedReader(new InputStreamReader(fs.open(pt)));
     String line = null;
     line = br.readLine
     while (line != null) {
      try {
        line = br.readLine
        System.out.println(line);
      }
    }
    

相关问题