一般情况下,我们使用Java访问hadoop distributed file system(hdfs)使用hadoop的相应api,添加以下的pom.xml依赖(这里以hadoop2.2.0版本为例):
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-mapreduce-client-core</artifactId> <version>2.2.0</version> </dependency>
在其中使用FileSystem就可以访问hdfs:
FileSystem fileSystem = null; try { Configuration conf = new Configuration(); fileSystem = FileSystem.get(conf); BufferedReader bufferedReader = = new BufferedReader(new InputStreamReader(fsInputStream));
但是需要注意的一点就是,只能在配置了hadoop环境的服务器上,通过hadoop jar的方式启动,hadoop jar的方式启动实际上调用的是org.apache.hadoop.util。RunJar作为入口。
RunJar会自动将此环境中的hadoop classpath设置,并初始化hadoop的环境变量等信息。
但是这种方式只能够写一个shell脚本来实现调用,其中使用hadoop jar的方式来调用,但是如果我们想要在比较特殊的环境下启动java进程,譬如在web server下(例如Tomcat)调用获取hdfs的信息,则不能够成功;或比如通过java -jar/-cp的方式来进行调用,得到的FileSystem.get(conf)并不是我们想要的。比如如果在本机执行该方法,就会得到本机磁盘相关文件系统,只有通过hadoop jar的方式调用返回DistributedFileSystem。
FileSystem类中还有一个方法,可以根据相应的URI来得到对应的FileSystem:
/** * Get a filesystem instance based on the uri, the passed * configuration and the user * @param uri of the filesystem * @param conf the configuration to use * @param user to perform the get as * @return the filesystem instance * @throws IOException * @throws InterruptedException */ public static FileSystem get(final URI uri, final Configuration conf, final String user) throws IOException, InterruptedException {
从hadoop file system环境中查找对应hadoop defaultFS配置:
<property> <name>fs.defaultFS</name> <value>hdfs://ns1</value>
就会曝出以下的错误,提示缺少一个类定义:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/util/PlatformName at org.apache.hadoop.security.UserGroupInformation.getOSLoginModuleName(UserGroupInformation.java:303) at org.apache.hadoop.security.UserGroupInformation.<clinit>(UserGroupInformation.java:348) at org.apache.hadoop.fs.FileSystem$Cache$Key.<init>(FileSystem.java:2590) at org.apache.hadoop.fs.FileSystem$Cache$Key.<init>(FileSystem.java:2582) at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2448) at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:367) at com.xxxx.HdfsMain.main(HdfsMain.java:21) Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.util.PlatformName at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ... 7 more
通过在网上查找的说法,此种情况下需要额外添加hadoop-auth的相关依赖:
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-auth</artifactId> <version>2.2.0</version> </dependency>
但是jar包添加进去后仍然不能够奏效,
Exception in thread "main" java.io.IOException: No FileSystem for scheme: hdfs at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2421) at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2428) at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:88) at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2467) at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2449) at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:367)
经过查看源代码,可以看出SERVICE_FILE_SYSTEMS中并没有存在hdfs中scheme:
public static Class<? extends FileSystem> getFileSystemClass(String scheme, Configuration conf) throws IOException { if (!FILE_SYSTEMS_LOADED) { loadFileSystems(); } Class<? extends FileSystem> clazz = null; if (conf != null) { clazz = (Class<? extends FileSystem>) conf.getClass("fs." + scheme + ".impl", null); } if (clazz == null) { clazz = SERVICE_FILE_SYSTEMS.get(scheme); } if (clazz == null) { throw new IOException("No FileSystem for scheme: " + scheme); } return clazz; }
可以手动采用Configuration设置fs.[filesystemname].impl的方式,手动将DistributedFileSystem注册进去:
conf.set("fs.hdfs.impl", DistributedFileSystem.class.getName());
这样启动后发现仍然有坑,因为ns1并不是真实的网络地址,地址配置在hdfs-site.xml文件中,我们的NameNode是两个随时可互相切换的HA服务器:
<property> <name>dfs.nameservices</name> <value>ns1</value> </property> <property> <name>dfs.ha.namenodes.ns1</name> <value>nn1,nn2</value> </property> <property> <name>dfs.namenode.rpc-address.ns1.nn1</name> <value>xxx1.cn:8020</value> </property> <property> <name>dfs.namenode.rpc-address.ns1.nn2</name> <value>xxx2.cn:8020</value> </property>
于是将fileSystem设置成其中的一台服务器,
fileSystem = FileSystem.get(URI.create("hdfs://xxx1.cn:8020"), conf)
这样终于成功了,注意,如果你连接上的是一个standby服务器,是不能够Read成功的!只有连接上active状态的服务器才能成功,那么如何确定哪台服务器当时是active呢,可以通过命令:
hdfs haadmin -getServiceState nn1 standby hdfs haadmin -getServiceState nn2 active
这表示nn2是active NameNode服务器。
那么问题就来了,如果这样的话,当NameNode发生自动切换时,是不能够智能地发生切换操作的,如何避免这个问题?
在Hadoop技术内幕 hadoop common和hdfs架构设计原理与实现一书中,专门有一章节介绍hadoop hdfs configuration的设置。
从其中可以看出整个Configuration的加载过程,如果我们在构造FileSystem的时候,加载服务端中的两个核心文件,比如将代码写成下面这种,是否能够最终成功呢?
String uri = “/file/config"; Configuration conf = new Configuration(); conf.addResource(new Path("/home/xxxx/hadoop/etc/hadoop/core-site.xml")); conf.addResource(new Path("/home/xxxx/hadoop/etc/hadoop/hdfs-site.xml")); fileSystem = FileSystem.get(conf); FileStatus[] fs = fileSystem.listStatus(new Path(uri)); for (FileStatus f : fs) { System.out.println(f.getPath()); }
答案是可以的,甚至都不需要采用带URI的函数。虽然绕了个大圈回到了原点,解决办法也非常简单,但通过这个过程的分析,可以使得我们可以熟悉整个FileSystem初始化的过程,也算是收获不小吧。
相关推荐
java整合spring和hadoop HDFS全部jar
标签:apache、hdfs、hadoop、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心...
标签:apache、hdfs、hadoop、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心...
java操作Hadoop源码之HDFS Java API操作-上传文件,附带所需全部jar包,欢迎下载学习。
标签:apache、hdfs、hadoop、jar包、java、API文档、中英对照版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...
标签:apache、hadoop、hdfs、client、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...
java操作Hadoop源码之HDFS Java API操作-创建目录,附带所需全部jar包,欢迎下载学习。
标签:apache、hadoop、hdfs、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请...
标签:apache、hdfs、hadoop、jar包、java、API文档、中英对照版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...
标签:apache、hadoop、hdfs、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心...
标签:apache、hadoop、hdfs、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请...
集合Maven,hdfs,mapreduce等相关所有jar包及依赖包
hadoop-hdfs-3.2.0.jar
java项目Hadoop依赖包,包含MapReduce、hdfs。
java操作hadoop之mapreduce计算整数的最大值和最小值实战源码,附带全部所需jar包,欢迎下载一起学习。
本依赖包在Loadrunner 11中测试通过,由于Loadrunner 11支持的是JDK1.6版本,而hadoop 2.6支持的也是JDK1.6版本,所以本文件中的Jar包主要是从hadoop 2.6.0中抽取。
Hadoop 架构是一个开源的、基于 Java 的编程框架,设计用于跨电脑集群来 处理大数据。Hadoop 是一个能够让用户轻松搭建和使用的分布式计算平台,能 够让用户轻松地在 Hadoop 上开发和运行处理海量数据的应用程序。 ...
并配置/etc/profile环境 export JAVA_HOME=/usr/local/jdk1.6 export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre:$PATH export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar 2、下载Hadoop 解压到每台服务器的/data...
java运行依赖jar包
java运行依赖jar包