如何用javaAPI访问hdfs文件
1.环境:借助阿里云服务器搭建的hadoop平台,hadoop版本3.0.3,伪分布式
2.操作:在idea里通过javaAPI读取hdfs文件里的内容
import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import org.junit.Test; public class HdfsDemoApp { @Test public static void main(String[] args) { try { //创建Configuration对象 Configuration conf = new Configuration(); //设置Hadoop的dfs客户端使用hostname访问datanode //conf.set("dfs.client.use.datanode.hostname", "true"); conf.set("fs.defaultFS", "hdfs://master:9000"); FileSystem fs = FileSystem.get(conf); // 打开hdfs上的文件并读取输出 Path hello = new Path("/user/hdfs/artist.txt"); FSDataInputStream ins = fs.open(hello); int ch = ins.read(); while (ch != -1) { System.out.print((char) ch); ch = ins.read(); } System.out.println(); } catch (IOException ioe) { ioe.printStackTrace(); } } }
3.遇到的问题:无法获取到数据块,报错:Could not obtain block
4.分析原因:文件夹和文件名都是存放在 NameNode 上的,本地可以通过公网访问 NameNode,所以创建文件夹和文件都可以,但是写数据的时候,NameNode 和DataNode 是通过内网通信的,NameNode 会返回给本地 DataNode 的内网 IP,本地就访问不了了。
4.分析原因:文件夹和文件名都是存放在 NameNode 上的,本地可以通过公网访问 NameNode,所以创建文件夹和文件都可以,但是写数据的时候,NameNode 和DataNode 是通过内网通信的,NameNode 会返回给本地 DataNode 的内网 IP,本地就访问不了了。
5.解决方案:让NameNode不返回DataNode的私网IP,而返回的是DataNode的主机名
方案一:在代码中添加配置信息(理论上应该是可行的,但不知是哪里出了问题,我没有成功)(弊端就是程序都要配置)
//创建Configuration对象 Configuration conf = new Configuration(); //设置Hadoop的dfs客户端使用hostname访问datanode conf.set("dfs.client.use.datanode.hostname", "true");方案二:修改hdfs-site.xml和core-site.xml并且把这两个配置文件放在IDEA的resources目录下,好处就是在一个项目中只需要配置一次,坏处就是当你用spark读取本地文件的时候,它会自动去读取hdfs上的文件,用file:///(\\\)+绝对路径可访问本地文件
1)hdfs-site.xml
<!--返回datanode的主机名--> <property> <description>only cofig in clients</description> <name>dfs.client.use.datanode.hostname</name> <value>true</value> </property>
2)core-site.xml
<configuration> <property> <name>hadoop.tmp.dir</name> <value>file:/opt/hadoop/tmp</value> </property> <property> <name>fs.defaultFS</name> <value>hdfs://master:9000</value> <!-- <value>hdfs://localhost:9000</value> --> </property> <property> <name>hadoop.proxyuser.hadoop.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.hadoop.groups</name> <value>*</value> </property> <!-- 是否在HDFS中开启权限检查 --> <property> <name>dfs.permissions.enabled</name> <value>false</value> </property> </configuration>
然后,在阿里云的***添加规则,手动添加DataNode用于数据传输服务端口 默认是 9866(hadoop3.0之前的端口是50010)。
附上hadoop3.x的端口变化:
Namenode ports: 50470 --> 9871, 50070 --> 9870, 8020 --> 9820 Secondary NN ports: 50091 --> 9869, 50090 --> 9868 Datanode ports: 50020 --> 9867, 50010 --> 9866, 50475 --> 9865, 50075 --> 9864
最后配置本地host映射
hosts文件在Windows下的路径为:
C:\Windows\System32\drivers\etc\hosts
在文件中添加:
公网IP 主机名(我的是master)