Big DataHDFS讲义(5)
文章目录
- 7.HDFS的javaAPI操作
- 创建maven工程并导入jar包
- 使用文件系统方式访问数据(掌握)
- 获取FileSystem的几种方式
- 递归遍历文件系统当中的所有文件
- 官方提供的API直接遍历
- 下载文件到本地
- hdfs上创建文件夹
- hdfs文件上传
- javaAPI基本操作
- HDFS权限问题以及伪造用户
- HDFS的小文件合并
- HDFS-Web界面介绍
- Overview
- Summary
- Datanodes
7.HDFS的javaAPI操作
由于cdh版本的所有的软件涉及版权的问题,所以并没有将所有的jar包托管到maven仓库当中去,而是托管在了CDH自己的服务器上面,所以我们默认去maven的仓库下载不到,需要自己手动的添加repository去CDH仓库进行下载,以下两个地址是官方文档说明,请仔细查阅
官方文档说明:CDH 5 Maven存储库
CDH仓库下载地址:Maven Artifacts for CDH 5.14.x
创建maven工程并导入jar包
<repositories><repository><id>cloudera</id><url>/</url></repository>
</repositories>
<dependencies><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-client</artifactId><version>2.6.0-mr1-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-common</artifactId><version>2.6.0-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-hdfs</artifactId><version>2.6.0-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-mapreduce-client-core</artifactId><version>2.6.0-cdh5.14.0</version></dependency><!-- --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>RELEASE</version></dependency>
</dependencies>
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.0</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><!-- <verbal>true</verbal>--></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.4.3</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><minimizeJar>true</minimizeJar></configuration></execution></executions></plugin><!-- <plugin><artifactId>maven-assembly-plugin </artifactId><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass>cn.itcast.Hadoop.db.DBToHdfs2</mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin>--></plugins>
</build>
- 使用url的方式访问数据(了解)
@Test
public void demo1()throws Exception{//第一步:注册hdfs 的url,让java代码能够识别hdfs的url形式URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());InputStream inputStream = null;FileOutputStream outputStream =null;//定义文件访问的url地址String url = "hdfs://192.168.52.100:8020/test/input/install.log";//打开文件输入流try {inputStream = new URL(url).openStream();outputStream = new FileOutputStream(new File("c:\\hello.txt"));IOUtils.copy(inputStream, outputStream);} catch (IOException e) {e.printStackTrace();}finally {IOUtils.closeQuietly(inputStream);IOUtils.closeQuietly(outputStream);}
}
如果执行出现以下错误,可以参见资料如何解决,也可以不用理会,不会影响程序的执行。记得配置完成环境变量之后重启开发工具
使用文件系统方式访问数据(掌握)
在 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 , 默 认 值 为 : file:/// , 则 获 取 的 将 不 是 一 个DistributedFileSystem 的实例,而是一个本地文件系统的客户端对象
获取FileSystem的几种方式
第一种方式获取FileSystem
@Test
public void getFileSystem() throws URISyntaxException, IOException {Configuration configuration = new Configuration();FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), configuration);System.out.println(fileSystem.toString());
}第二种获取FileSystem类的方式
@Test
public void getFileSystem2() throws URISyntaxException, IOException {Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.52.100:8020");FileSystem fileSystem = FileSystem.get(new URI("/"), configuration);System.out.println(fileSystem.toString());
}第三种获取FileSystem类的方式
@Test
public void getFileSystem3() throws URISyntaxException, IOException {Configuration configuration = new Configuration();FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://192.168.52.100:8020"), configuration);System.out.println(fileSystem.toString());
}第四种获取FileSystem类的方式
@Test
public void getFileSystem4() throws Exception{Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.52.100:8020");FileSystem fileSystem = FileSystem.newInstance(configuration);System.out.println(fileSystem.toString());
}
递归遍历文件系统当中的所有文件
通过递归遍历hdfs文件系统
@Test
public void listFile() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));for (FileStatus fileStatus : fileStatuses) {if(fileStatus.isDirectory()){Path path = fileStatus.getPath();listAllFiles(fileSystem,path);}else{System.out.println("文件路径为"+fileStatus.getPath().toString());}}
}public void listAllFiles(FileSystem fileSystem,Path path) throws Exception{FileStatus[] fileStatuses = fileSystem.listStatus(path);for (FileStatus fileStatus : fileStatuses) {if(fileStatus.isDirectory()){listAllFiles(fileSystem,fileStatus.getPath());}else{Path path1 = fileStatus.getPath();System.out.println("文件路径为"+path1);}}
}
官方提供的API直接遍历
/*** 递归遍历官方提供的API版本* @throws Exception*/
@Test
public void listMyFiles()throws Exception{//获取fileSystem类FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());//获取RemoteIterator 得到所有的文件或者文件夹,第一个参数指定遍历的路径,第二个参数表示是否要递归遍历RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);while (locatedFileStatusRemoteIterator.hasNext()){LocatedFileStatus next = locatedFileStatusRemoteIterator.next();System.out.println(next.getPath().toString());}fileSystem.close();
}
下载文件到本地
/*** 拷贝文件的到本地* @throws Exception*/
@Test
public void getFileToLocal()throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());FSDataInputStream open = fileSystem.open(new Path("/test/input/install.log"));FileOutputStream fileOutputStream = new FileOutputStream(new File("c:\\install.log"));IOUtils.copy(open,fileOutputStream );IOUtils.closeQuietly(open);IOUtils.closeQuietly(fileOutputStream);fileSystem.close();
}
hdfs上创建文件夹
@Test
public void mkdirs() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));fileSystem.close();
}
hdfs文件上传
@Test
public void putData() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));fileSystem.close();
}
javaAPI基本操作
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;import java.net.URI;
import java.net.URISyntaxException;public class demo {//该类的对象封转了客户端或者服务器的配置static Configuration conf=new Configuration();//获取指定路径所有文件public static void listStatus() throws Exception {//该类的对象是一个文件系统对象FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);//获取某一目录下的所有文件FileStatus stats[]=hdfs.listStatus(new Path("/"));//遍历输出for(int i = 0; i < stats.length; ++i)System.out.println(stats[i].getPath().toString());hdfs.close();}//重命名public static void rename() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path frpaht=new Path("/aaa");Path topath=new Path("/aaaaaaa");boolean isRename=hdfs.rename(frpaht, topath);String result=isRename?"修改成功!":"修改失败!";System.out.println(result);}//获取文件日期public static void GetTime() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);FileStatus fileStatus=hdfs.getFileStatus(new Path("/yarn-daemons.txt"));long modiTime=fileStatus.getModificationTime();System.out.println(modiTime);}//删除文件public static void deletefile() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);boolean isDeleted=hdfs.delete(new Path("/user/new"),true);System.out.println("Delete?"+isDeleted);}//创建文件夹public static void mkdir () throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);boolean bool2=hdfs.mkdirs(new Path("/user/new"));if (bool2){System.out.println("创建成功!!");}else{System.out.println("创建失败!!");}}//创建数据public static void AddFile() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);byte[] buff="hello hadoop world!\r\n hadoop ".getBytes();FSDataOutputStream outputStream=hdfs.create(new Path("/tmp/file.txt"));outputStream.write(buff,0,buff.length);outputStream.close();}//上传数据public static void put() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path src =new Path("C:/123.py");Path dst =new Path("/");hdfs.copyFromLocalFile(src, dst);}//检查目录是否存在public static void check() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path findf=new Path("/abc");boolean isExists=hdfs.exists(findf);System.out.println("Exist?"+isExists);}
HDFS权限问题以及伪造用户
首先停止hdfs集群,在node01机器上执行以下命令
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0
[root@node01 hadoop-2.6.0-cdh5.14.0]# sbin/stop-dfs.sh修改node01机器上的hdfs-site.xml当中的配置文件
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop[root@node01 hadoop]# vim hdfs-site.xml
在hdfs-site.xml添加如下配置 开启权限认证 (每个节点都要配置)
<property><name>dfs.permissions</name><value>true</value>
</property>有权限,必然有管理员
linux 超级管理员是 root
HDFS 超级管理员是 hdfs(部分大数据平台)修改完成之后配置文件发送到其他机器上面去scp hdfs-site.xml node02:$PWDscp hdfs-site.xml node03:$PWD重启hdfs集群
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0
[root@node01 hadoop-2.6.0-cdh5.14.0]# sbin/start-dfs.sh随意上传一些文件到我们Hadoop集群当中准备测试使用
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop
[root@node01 hadoop]# hdfs dfs -mkdir /config
[root@node01 hadoop]# hdfs dfs -put *.xml /config
[root@node01 hadoop]# hdfs dfs -chmod 600 /config/core-site.xml
- 使用代码准备下载文件
@Test
public void getConfig()throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration(),"root");fileSystem.copyToLocalFile(new Path("/config/core-site.xml"),new Path("file:///c:/core-site.xml"));fileSystem.close();
}
HDFS的小文件合并
由于Hadoop擅长存储大文件,因为大文件的元数据信息比较少,如果Hadoop集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理。
在我们的hdfs 的shell命令模式下,可以通过命令行将很多的hdfs文件合并成一个大文件下载到本地,命令如下
[root@node01 ~]# cd /export/servers
[root@node01 servers]# hdfs dfs -getmerge /config/*.xml ./hello.xml
既然可以在下载的时候将这些小文件合并成一个大文件一起下载,那么肯定就可以在上传的时候将小文件合并到一个大文件里面去
代码如下:
/*** 将多个本地系统文件,上传到hdfs,并合并成一个大的文件* @throws Exception*/
@Test
public void mergeFile() throws Exception{//获取分布式文件系统FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration(),"root");FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.xml"));//获取本地文件系统LocalFileSystem local = FileSystem.getLocal(new Configuration());//通过本地文件系统获取文件列表,为一个集合FileStatus[] fileStatuses = local.listStatus(new Path("file:///F:\\上传小文件合并"));for (FileStatus fileStatus : fileStatuses) {FSDataInputStream inputStream = local.open(fileStatus.getPath());IOUtils.copy(inputStream,outputStream);IOUtils.closeQuietly(inputStream);}IOUtils.closeQuietly(outputStream);local.close();fileSystem.close();
}
总结
HDFS -> Local 使用HDFS提供的-getmerge 方法
Local -> HDFS 遍历每个小文件追加到一个文件,在进行上传(这个文件不在HDFS)
HDFS-Web界面介绍
当我们启动HDFS集群后,然后通过http://master:50070/去访问HDFS WEB UI的时候,我们会经常使用Utilities下的Browse the file system去查看HDFS中的文件,如下:
然后就会出现HDFS中的根目录下所有的文件:
上面的方式是我们常见的访问HDFS文件的方式之一,这种使用的方式也是很方便的。
当我们启动HDFS集群后,我们可以通过http://master:50070来访问HDFS集群,其中,master是NameNode所在机器的名称。下面的就是HDFS WEB UI的七个大模块:
这篇文章,我们重点分别来详细看一下Overview、Datanodes以及Utilities三个模块
Overview
- 第1处的master:9999表示当前HDFS集群的基本路径。这个值是从配置core-site.xml中的fs.defaultFS获取到的。
- 第2处的Started表示集群启动的时间
- 第3处的Version表示我们使用的Hadoop的版本,我们使用的是2.7.5的Hadoop
- 第4处的Compiled表示Hadoop的安装包(hadoop-2.7.5.tar.gz)编译打包的时间,以及编译的作者等信息
- 第5处的Cluster ID表示当前HDFS集群的唯一ID
- 第6处的Block Pool ID表示当前HDFS的当前的NameNode的ID,我们知道通过HDFS Federation (联盟)的配置,我们可以为一个HDFS集群配置多个NameNode,每一个NameNode都会分配一个Block Pool ID
Summary
- 第1处的Security is off表示当前的HDFS集群没有启动安全机制
- 第2处的Safemode is off表示当前的HDFS集群不在安全模式,如果显示的是Safemode is on的话,则表示集群处于安全模式,那么这个时候的HDFS集群是不能用的
- 第3处表示当前HDFS集群包含了3846个文件或者目录,以及1452个数据块,那么在NameNode的内存中肯定有3846 + 1452 = 5298个文件系统的对象存在
- 第4处表示NameNode的堆内存(Heap Memory)是312MB,已经使用了287.3MB,堆内存最大为889MB,对
- 第5处表示NameNode的非堆内存的使用情况,有效的非堆内存是61.44MB,已经使用了60.36MB。没有限制最大的非堆内存,但是非堆内存加上堆内存不能大于虚拟机申请的最大内存(默认是1000M)
- 第6处的Configured Capacity表示当前HDFS集群的磁盘总容量。这个值是通过:Total Disk Space - Reserved Space计算出来的。Total Disk Space表示所在机器所在磁盘的总大小,而Reserved Space表示一个预留给操作系统层面操作的空间。Reserved space空间可以通过dfs.datanode.du.reserved(默认值是0)在hdfs-site.xml文件中进行配置。
我们这边的总容量为什么是:33.97GB呢,我们可以通过du -h看一下两个slave的磁盘使用情况,如下:
上面 17GB + 17GB = 34GB,而且我们没有配置Reserved Space,所以HDFS总容量就是33.97GB(有一点点的误差可以忽略)
- 第7处DFS Used表示HDFS已经使用的磁盘容量,说白了就是HDFS文件系统上文件的总大小(包含了每一个数据块的副本的大小)
- 第8处Non DFS Used表示在任何DataNodes节点上,不在配置的dfs.datanode.data.dir里面的数据所占的磁盘容量。其实就是非HDFS文件占用的磁盘容量
配置dfs.datanode.data.dir就是DataNode数据存储的文件目录
- 第9处DFS Remaining = Configured Capacity - DFS Used - Non DFS Used。这是HDFS上实际可以使用的总容量
- 第10处Block Pool Used表示当前的Block Pool使用的磁盘容量
- 第11处DataNodes usages%表示所有的DataNode的磁盘使用情况(最小/平均/最大/方差)
- 第12处Live Nodes表示存活的DataNode的数量。Decommissioned表示已经下线的DataNode
- 第13处Dead Nodes表示已经死了的DataNode的数量。Decommissioned表示已经下线的DataNode
- 第14处Decommissioning Nodes表示正在下线的DataNode的数量。
- 第15处Total Datanode Volume Failures表示DataNode上数据块的损坏大小
- 第16处Number of Under-Replicated Blocks表示没有达到备份数要求的数据块的数量
- 第17处Number of Blocks Pending Deletion表示正要被删除的数据块
- 第18处Block Deletion Start Time表示可以删除数据块的时间。这个值等于集群启动的时间加上配置dfs.namenode.startup.delay.block.deletion.sec的时间,其中配置dfs.namenode.startup.delay.block.deletion.sec默认是0秒
Datanodes
上面有一个Admin State我们有必要说明下,Admin State可以取如下的值:
- 1.In Service,表示这个DataNode正常
- 2.Decommission In Progress,表示这个DataNode正在下线
- 3.Decommissioned,表示这个DataNode已经下线
- 4.Entering Maintenance,表示这个DataNode正进入维护状态
- 5.In Maintenance,表示这个DataNode已经在维护状态
我们这里详细总结下Browse the file system,对于Logs我们在HDFS日志的查看总结中讲解
当我们点击Browse the file system时,我么会进入到如下的界面:
上图每一个字段的解释如下: - Permission:表示该文件或者目录的权限,和Linux的文件权限规则是一样的
- Owner:表示该文件或者目录的所有者
- Group:表示该文件或者目录的所有者属于的组
- Size:表示该文件或者目录的大小,如果是目录的话则一直显示0B
- Last Modified:表示该文件或者目录的最后修改时间
- Replication:表示该文件或者目录的备份数,如果是目录的话则一直显示0
- Block Size:表示该文件的数据块的大小,如果是目录的话则一直显示0B
- Name:表示文件或者目录的名字
我们可以通过鼠标点击Name来访问对应的文件目录或者文件:
当我们访问的是目录的时候,则是去查看该目录下有哪些子文件或者子目录。
当我们访问的是文件的时候,我们查看的是文件的详细信息,比如,我们访问文件/user/omneo.csv文件:
Journal Manager:Journal Node 存储EditLog数据的路径
State: Journal Node 存储EditLog数据的文件名
NameNode 存储数据的路径
NameNode存储edits的路径
/export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/edits
NameNode存储fsimage的路径
/export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatas
Storage Type : 集群存储类型 DISK(磁盘)
Configured Capacity: 配置容量 135.01 GB
Capacity Used: 使用的容量 355.01 MB (0.26%)
Capacity Remaining:剩余容量 117.49 GB (87.02%)
Block Pool Used: 使用的块池 355.01 MB
Nodes In Service:服务中的节点 3
Datanode usage histogram: 数据节点使用率柱状图
Disk usage of each DataNode (%):每个数据节点的磁盘使用率(%)
In operation:运行中的节点
Entering Maintenance: 进入维护的节点列表
Decommissioning: 退役的节点列表
Snapshot Summary:快照摘要
Snapshottable directories : 快照目录列表:2
Snapshotted directories: 已创建的快照目录:4
Startup Progress:集群启动时加载的fsimage和edits
启动时加载的fsimage: fsimage_0000000000000000537
启动时加载的edits:edits_0000000000000000538-0000000000000000538
Big DataHDFS讲义(5)
文章目录
- 7.HDFS的javaAPI操作
- 创建maven工程并导入jar包
- 使用文件系统方式访问数据(掌握)
- 获取FileSystem的几种方式
- 递归遍历文件系统当中的所有文件
- 官方提供的API直接遍历
- 下载文件到本地
- hdfs上创建文件夹
- hdfs文件上传
- javaAPI基本操作
- HDFS权限问题以及伪造用户
- HDFS的小文件合并
- HDFS-Web界面介绍
- Overview
- Summary
- Datanodes
7.HDFS的javaAPI操作
由于cdh版本的所有的软件涉及版权的问题,所以并没有将所有的jar包托管到maven仓库当中去,而是托管在了CDH自己的服务器上面,所以我们默认去maven的仓库下载不到,需要自己手动的添加repository去CDH仓库进行下载,以下两个地址是官方文档说明,请仔细查阅
官方文档说明:CDH 5 Maven存储库
CDH仓库下载地址:Maven Artifacts for CDH 5.14.x
创建maven工程并导入jar包
<repositories><repository><id>cloudera</id><url>/</url></repository>
</repositories>
<dependencies><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-client</artifactId><version>2.6.0-mr1-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-common</artifactId><version>2.6.0-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-hdfs</artifactId><version>2.6.0-cdh5.14.0</version></dependency><dependency><groupId>org.apache.Hadoop</groupId><artifactId>Hadoop-mapreduce-client-core</artifactId><version>2.6.0-cdh5.14.0</version></dependency><!-- --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>RELEASE</version></dependency>
</dependencies>
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.0</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><!-- <verbal>true</verbal>--></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.4.3</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><minimizeJar>true</minimizeJar></configuration></execution></executions></plugin><!-- <plugin><artifactId>maven-assembly-plugin </artifactId><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass>cn.itcast.Hadoop.db.DBToHdfs2</mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin>--></plugins>
</build>
- 使用url的方式访问数据(了解)
@Test
public void demo1()throws Exception{//第一步:注册hdfs 的url,让java代码能够识别hdfs的url形式URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());InputStream inputStream = null;FileOutputStream outputStream =null;//定义文件访问的url地址String url = "hdfs://192.168.52.100:8020/test/input/install.log";//打开文件输入流try {inputStream = new URL(url).openStream();outputStream = new FileOutputStream(new File("c:\\hello.txt"));IOUtils.copy(inputStream, outputStream);} catch (IOException e) {e.printStackTrace();}finally {IOUtils.closeQuietly(inputStream);IOUtils.closeQuietly(outputStream);}
}
如果执行出现以下错误,可以参见资料如何解决,也可以不用理会,不会影响程序的执行。记得配置完成环境变量之后重启开发工具
使用文件系统方式访问数据(掌握)
在 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 , 默 认 值 为 : file:/// , 则 获 取 的 将 不 是 一 个DistributedFileSystem 的实例,而是一个本地文件系统的客户端对象
获取FileSystem的几种方式
第一种方式获取FileSystem
@Test
public void getFileSystem() throws URISyntaxException, IOException {Configuration configuration = new Configuration();FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), configuration);System.out.println(fileSystem.toString());
}第二种获取FileSystem类的方式
@Test
public void getFileSystem2() throws URISyntaxException, IOException {Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.52.100:8020");FileSystem fileSystem = FileSystem.get(new URI("/"), configuration);System.out.println(fileSystem.toString());
}第三种获取FileSystem类的方式
@Test
public void getFileSystem3() throws URISyntaxException, IOException {Configuration configuration = new Configuration();FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://192.168.52.100:8020"), configuration);System.out.println(fileSystem.toString());
}第四种获取FileSystem类的方式
@Test
public void getFileSystem4() throws Exception{Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.52.100:8020");FileSystem fileSystem = FileSystem.newInstance(configuration);System.out.println(fileSystem.toString());
}
递归遍历文件系统当中的所有文件
通过递归遍历hdfs文件系统
@Test
public void listFile() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));for (FileStatus fileStatus : fileStatuses) {if(fileStatus.isDirectory()){Path path = fileStatus.getPath();listAllFiles(fileSystem,path);}else{System.out.println("文件路径为"+fileStatus.getPath().toString());}}
}public void listAllFiles(FileSystem fileSystem,Path path) throws Exception{FileStatus[] fileStatuses = fileSystem.listStatus(path);for (FileStatus fileStatus : fileStatuses) {if(fileStatus.isDirectory()){listAllFiles(fileSystem,fileStatus.getPath());}else{Path path1 = fileStatus.getPath();System.out.println("文件路径为"+path1);}}
}
官方提供的API直接遍历
/*** 递归遍历官方提供的API版本* @throws Exception*/
@Test
public void listMyFiles()throws Exception{//获取fileSystem类FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());//获取RemoteIterator 得到所有的文件或者文件夹,第一个参数指定遍历的路径,第二个参数表示是否要递归遍历RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);while (locatedFileStatusRemoteIterator.hasNext()){LocatedFileStatus next = locatedFileStatusRemoteIterator.next();System.out.println(next.getPath().toString());}fileSystem.close();
}
下载文件到本地
/*** 拷贝文件的到本地* @throws Exception*/
@Test
public void getFileToLocal()throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());FSDataInputStream open = fileSystem.open(new Path("/test/input/install.log"));FileOutputStream fileOutputStream = new FileOutputStream(new File("c:\\install.log"));IOUtils.copy(open,fileOutputStream );IOUtils.closeQuietly(open);IOUtils.closeQuietly(fileOutputStream);fileSystem.close();
}
hdfs上创建文件夹
@Test
public void mkdirs() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));fileSystem.close();
}
hdfs文件上传
@Test
public void putData() throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration());fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));fileSystem.close();
}
javaAPI基本操作
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;import java.net.URI;
import java.net.URISyntaxException;public class demo {//该类的对象封转了客户端或者服务器的配置static Configuration conf=new Configuration();//获取指定路径所有文件public static void listStatus() throws Exception {//该类的对象是一个文件系统对象FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);//获取某一目录下的所有文件FileStatus stats[]=hdfs.listStatus(new Path("/"));//遍历输出for(int i = 0; i < stats.length; ++i)System.out.println(stats[i].getPath().toString());hdfs.close();}//重命名public static void rename() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path frpaht=new Path("/aaa");Path topath=new Path("/aaaaaaa");boolean isRename=hdfs.rename(frpaht, topath);String result=isRename?"修改成功!":"修改失败!";System.out.println(result);}//获取文件日期public static void GetTime() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);FileStatus fileStatus=hdfs.getFileStatus(new Path("/yarn-daemons.txt"));long modiTime=fileStatus.getModificationTime();System.out.println(modiTime);}//删除文件public static void deletefile() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);boolean isDeleted=hdfs.delete(new Path("/user/new"),true);System.out.println("Delete?"+isDeleted);}//创建文件夹public static void mkdir () throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);boolean bool2=hdfs.mkdirs(new Path("/user/new"));if (bool2){System.out.println("创建成功!!");}else{System.out.println("创建失败!!");}}//创建数据public static void AddFile() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);byte[] buff="hello hadoop world!\r\n hadoop ".getBytes();FSDataOutputStream outputStream=hdfs.create(new Path("/tmp/file.txt"));outputStream.write(buff,0,buff.length);outputStream.close();}//上传数据public static void put() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path src =new Path("C:/123.py");Path dst =new Path("/");hdfs.copyFromLocalFile(src, dst);}//检查目录是否存在public static void check() throws Exception {FileSystem hdfs=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);Path findf=new Path("/abc");boolean isExists=hdfs.exists(findf);System.out.println("Exist?"+isExists);}
HDFS权限问题以及伪造用户
首先停止hdfs集群,在node01机器上执行以下命令
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0
[root@node01 hadoop-2.6.0-cdh5.14.0]# sbin/stop-dfs.sh修改node01机器上的hdfs-site.xml当中的配置文件
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop[root@node01 hadoop]# vim hdfs-site.xml
在hdfs-site.xml添加如下配置 开启权限认证 (每个节点都要配置)
<property><name>dfs.permissions</name><value>true</value>
</property>有权限,必然有管理员
linux 超级管理员是 root
HDFS 超级管理员是 hdfs(部分大数据平台)修改完成之后配置文件发送到其他机器上面去scp hdfs-site.xml node02:$PWDscp hdfs-site.xml node03:$PWD重启hdfs集群
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0
[root@node01 hadoop-2.6.0-cdh5.14.0]# sbin/start-dfs.sh随意上传一些文件到我们Hadoop集群当中准备测试使用
[root@node01 ~]# cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop
[root@node01 hadoop]# hdfs dfs -mkdir /config
[root@node01 hadoop]# hdfs dfs -put *.xml /config
[root@node01 hadoop]# hdfs dfs -chmod 600 /config/core-site.xml
- 使用代码准备下载文件
@Test
public void getConfig()throws Exception{FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration(),"root");fileSystem.copyToLocalFile(new Path("/config/core-site.xml"),new Path("file:///c:/core-site.xml"));fileSystem.close();
}
HDFS的小文件合并
由于Hadoop擅长存储大文件,因为大文件的元数据信息比较少,如果Hadoop集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理。
在我们的hdfs 的shell命令模式下,可以通过命令行将很多的hdfs文件合并成一个大文件下载到本地,命令如下
[root@node01 ~]# cd /export/servers
[root@node01 servers]# hdfs dfs -getmerge /config/*.xml ./hello.xml
既然可以在下载的时候将这些小文件合并成一个大文件一起下载,那么肯定就可以在上传的时候将小文件合并到一个大文件里面去
代码如下:
/*** 将多个本地系统文件,上传到hdfs,并合并成一个大的文件* @throws Exception*/
@Test
public void mergeFile() throws Exception{//获取分布式文件系统FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration(),"root");FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.xml"));//获取本地文件系统LocalFileSystem local = FileSystem.getLocal(new Configuration());//通过本地文件系统获取文件列表,为一个集合FileStatus[] fileStatuses = local.listStatus(new Path("file:///F:\\上传小文件合并"));for (FileStatus fileStatus : fileStatuses) {FSDataInputStream inputStream = local.open(fileStatus.getPath());IOUtils.copy(inputStream,outputStream);IOUtils.closeQuietly(inputStream);}IOUtils.closeQuietly(outputStream);local.close();fileSystem.close();
}
总结
HDFS -> Local 使用HDFS提供的-getmerge 方法
Local -> HDFS 遍历每个小文件追加到一个文件,在进行上传(这个文件不在HDFS)
HDFS-Web界面介绍
当我们启动HDFS集群后,然后通过http://master:50070/去访问HDFS WEB UI的时候,我们会经常使用Utilities下的Browse the file system去查看HDFS中的文件,如下:
然后就会出现HDFS中的根目录下所有的文件:
上面的方式是我们常见的访问HDFS文件的方式之一,这种使用的方式也是很方便的。
当我们启动HDFS集群后,我们可以通过http://master:50070来访问HDFS集群,其中,master是NameNode所在机器的名称。下面的就是HDFS WEB UI的七个大模块:
这篇文章,我们重点分别来详细看一下Overview、Datanodes以及Utilities三个模块
Overview
- 第1处的master:9999表示当前HDFS集群的基本路径。这个值是从配置core-site.xml中的fs.defaultFS获取到的。
- 第2处的Started表示集群启动的时间
- 第3处的Version表示我们使用的Hadoop的版本,我们使用的是2.7.5的Hadoop
- 第4处的Compiled表示Hadoop的安装包(hadoop-2.7.5.tar.gz)编译打包的时间,以及编译的作者等信息
- 第5处的Cluster ID表示当前HDFS集群的唯一ID
- 第6处的Block Pool ID表示当前HDFS的当前的NameNode的ID,我们知道通过HDFS Federation (联盟)的配置,我们可以为一个HDFS集群配置多个NameNode,每一个NameNode都会分配一个Block Pool ID
Summary
- 第1处的Security is off表示当前的HDFS集群没有启动安全机制
- 第2处的Safemode is off表示当前的HDFS集群不在安全模式,如果显示的是Safemode is on的话,则表示集群处于安全模式,那么这个时候的HDFS集群是不能用的
- 第3处表示当前HDFS集群包含了3846个文件或者目录,以及1452个数据块,那么在NameNode的内存中肯定有3846 + 1452 = 5298个文件系统的对象存在
- 第4处表示NameNode的堆内存(Heap Memory)是312MB,已经使用了287.3MB,堆内存最大为889MB,对
- 第5处表示NameNode的非堆内存的使用情况,有效的非堆内存是61.44MB,已经使用了60.36MB。没有限制最大的非堆内存,但是非堆内存加上堆内存不能大于虚拟机申请的最大内存(默认是1000M)
- 第6处的Configured Capacity表示当前HDFS集群的磁盘总容量。这个值是通过:Total Disk Space - Reserved Space计算出来的。Total Disk Space表示所在机器所在磁盘的总大小,而Reserved Space表示一个预留给操作系统层面操作的空间。Reserved space空间可以通过dfs.datanode.du.reserved(默认值是0)在hdfs-site.xml文件中进行配置。
我们这边的总容量为什么是:33.97GB呢,我们可以通过du -h看一下两个slave的磁盘使用情况,如下:
上面 17GB + 17GB = 34GB,而且我们没有配置Reserved Space,所以HDFS总容量就是33.97GB(有一点点的误差可以忽略)
- 第7处DFS Used表示HDFS已经使用的磁盘容量,说白了就是HDFS文件系统上文件的总大小(包含了每一个数据块的副本的大小)
- 第8处Non DFS Used表示在任何DataNodes节点上,不在配置的dfs.datanode.data.dir里面的数据所占的磁盘容量。其实就是非HDFS文件占用的磁盘容量
配置dfs.datanode.data.dir就是DataNode数据存储的文件目录
- 第9处DFS Remaining = Configured Capacity - DFS Used - Non DFS Used。这是HDFS上实际可以使用的总容量
- 第10处Block Pool Used表示当前的Block Pool使用的磁盘容量
- 第11处DataNodes usages%表示所有的DataNode的磁盘使用情况(最小/平均/最大/方差)
- 第12处Live Nodes表示存活的DataNode的数量。Decommissioned表示已经下线的DataNode
- 第13处Dead Nodes表示已经死了的DataNode的数量。Decommissioned表示已经下线的DataNode
- 第14处Decommissioning Nodes表示正在下线的DataNode的数量。
- 第15处Total Datanode Volume Failures表示DataNode上数据块的损坏大小
- 第16处Number of Under-Replicated Blocks表示没有达到备份数要求的数据块的数量
- 第17处Number of Blocks Pending Deletion表示正要被删除的数据块
- 第18处Block Deletion Start Time表示可以删除数据块的时间。这个值等于集群启动的时间加上配置dfs.namenode.startup.delay.block.deletion.sec的时间,其中配置dfs.namenode.startup.delay.block.deletion.sec默认是0秒
Datanodes
上面有一个Admin State我们有必要说明下,Admin State可以取如下的值:
- 1.In Service,表示这个DataNode正常
- 2.Decommission In Progress,表示这个DataNode正在下线
- 3.Decommissioned,表示这个DataNode已经下线
- 4.Entering Maintenance,表示这个DataNode正进入维护状态
- 5.In Maintenance,表示这个DataNode已经在维护状态
我们这里详细总结下Browse the file system,对于Logs我们在HDFS日志的查看总结中讲解
当我们点击Browse the file system时,我么会进入到如下的界面:
上图每一个字段的解释如下: - Permission:表示该文件或者目录的权限,和Linux的文件权限规则是一样的
- Owner:表示该文件或者目录的所有者
- Group:表示该文件或者目录的所有者属于的组
- Size:表示该文件或者目录的大小,如果是目录的话则一直显示0B
- Last Modified:表示该文件或者目录的最后修改时间
- Replication:表示该文件或者目录的备份数,如果是目录的话则一直显示0
- Block Size:表示该文件的数据块的大小,如果是目录的话则一直显示0B
- Name:表示文件或者目录的名字
我们可以通过鼠标点击Name来访问对应的文件目录或者文件:
当我们访问的是目录的时候,则是去查看该目录下有哪些子文件或者子目录。
当我们访问的是文件的时候,我们查看的是文件的详细信息,比如,我们访问文件/user/omneo.csv文件:
Journal Manager:Journal Node 存储EditLog数据的路径
State: Journal Node 存储EditLog数据的文件名
NameNode 存储数据的路径
NameNode存储edits的路径
/export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/edits
NameNode存储fsimage的路径
/export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatas
Storage Type : 集群存储类型 DISK(磁盘)
Configured Capacity: 配置容量 135.01 GB
Capacity Used: 使用的容量 355.01 MB (0.26%)
Capacity Remaining:剩余容量 117.49 GB (87.02%)
Block Pool Used: 使用的块池 355.01 MB
Nodes In Service:服务中的节点 3
Datanode usage histogram: 数据节点使用率柱状图
Disk usage of each DataNode (%):每个数据节点的磁盘使用率(%)
In operation:运行中的节点
Entering Maintenance: 进入维护的节点列表
Decommissioning: 退役的节点列表
Snapshot Summary:快照摘要
Snapshottable directories : 快照目录列表:2
Snapshotted directories: 已创建的快照目录:4
Startup Progress:集群启动时加载的fsimage和edits
启动时加载的fsimage: fsimage_0000000000000000537
启动时加载的edits:edits_0000000000000000538-0000000000000000538
发布评论