1. HDFS的JAVA API操作
HDFS在生产应用中主要是客户端的开发,其核心步骤是从HDFS提供的api中构造一个HDFS的访问客户端对象,然后通过该客户端对象操作(增删改查)HDFS上的文件。
1.1. 搭建开发环境
创建Maven工程,引入pom依赖
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.4</version>
</dependency>
</dependencies>
配置windows平台Hadoop环境
在windows上做HDFS客户端应用开发,需要设置Hadoop环境,而且要求是windows平台编译的Hadoop,不然会报以下的错误:
Failed to locate the winutils binary in the hadoop binary path java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
为此我们需要进行如下的操作:
A、在windows平台下编译Hadoop源码(可以参考资料编译,但不推荐)
B、使用已经编译好的Windows版本Hadoop:
hadoop-2.7.4-with-windows.tar.gz
C、解压一份到windows的任意一个目录下
D、在windows系统中配置HADOOP_HOME指向你解压的安装包目录
E、在windows系统的path变量中加入HADOOP_HOME的bin目录
1.2. 构造客户端对象
在java中操作HDFS,主要涉及以下Class:
Configuration:该类的对象封转了客户端或者服务器的配置;
FileSystem:该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象。
FileSystem fs = FileSystem.get(conf)
get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: [url=]file:///[/url],则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。
1.3. 示例代码
Configuration conf = new Configuration();
//这里指定使用的是hdfs文件系统
conf.set("fs.defaultFS", "hdfs://node-21:9000");
//通过如下的方式进行客户端身份的设置
System.setProperty("HADOOP_USER_NAME", "root");
//通过FileSystem的静态方法获取文件系统客户端对象
FileSystem fs = FileSystem.get(conf);
//也可以通过如下的方式去指定文件系统的类型 并且同时设置用户身份
//FileSystem fs = FileSystem.get(new URI("hdfs://node-21:9000"), conf, "root");
//创建一个目录
fs.create(new Path("/hdfsbyjava-ha"), false);
//上传一个文件
fs.copyFromLocalFile(new Path("e:/hello.sh"), new Path("/hdfsbyjava-ha"));
//关闭我们的文件系统
fs.close();
其他更多操作如文件增删改查请查看实例代码。
Stream流形式操作
public void testUpload() throws Exception {
FSDataOutputStream outputStream = fs.create(new Path("/1.txt"), true);
FileInputStream inputStream = new FileInputStream("D:\\1.txt");
IOUtils.copy(inputStream, outputStream);
}
2. 案例:shell定时采集数据至HDFS
上线的网站每天都会产生日志数据。假如有这样的需求:要求在凌晨24点开始操作前一天产生的日志文件,准实时上传至HDFS集群上。
该如何实现?实现后能否实现周期性上传需求?如何定时?
2.1. 技术分析
HDFS SHELL:
hadoop fs –put //满足上传文件,不能满足定时、周期性传入。
Linux crontab:
crontab -e
0 0 * /shell/ uploadFile2Hdfs.sh //每天凌晨12:00执行一次
2.2. 实现流程
一般日志文件生成的逻辑由业务系统决定,比如每小时滚动一次,或者一定大小滚动一次,避免单个日志文件过大不方便操作。
比如滚动后的文件命名为access.log.x,其中x为数字。正在进行写的日志文件叫做access.log。这样的话,如果日志文件后缀是1\2\3等数字,则该文件满足需求可以上传,就把该文件移动到准备上传的工作区间目录。工作区间有文件之后,可以使用hadoop put命令将文件上传。
2.3. 代码实现