文章目录
1.分布式文件系统HDFS
1.HDFS的来源
HDFS:Hadoop Distributed File system(hadoop分布式文件系统)
HDFS起源于Google的GFS论文(GFS,Mapreduce,BigTable为google的旧的三驾马车)HBASE
(1) 发表于2003年10月
(2)HDFS是GFS的克隆版
(3)易于扩展的分布式文件系统
(4)运行在大量普通廉价机器上,提供容错机制
(5)为大量用户提供性能不错的文件存取服务
2.HDFS的架构图之基础架构
2.1 master/slave 架构
NameNode是一个中心服务器,单一节点(简化系统的设计和实现),负责管理文件系统的名字空间(namespace)以及客户端对文件的访问
2.2 名字空间(NameSpace)
HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。
Namenode 负责维护文件系统的名字空间,任何对文件系统名字空间或属性的修改都将被Namenode 记录下来。
HDFS 会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,
形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data。
2.3 文件操作
namenode是负责文件元数据的操作,datanode负责处理文件内容的读写请求,跟文件内容相关的数据流不经过Namenode,只询问它跟哪个dataNode联系,否则NameNode会成为系统的瓶颈
2.4副本机制
为了容错,文件的所有 block 都会有副本。每个文件的 block 大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可以在之后改变。
2.5心跳机制
NameNode全权管理数据的复制,它周期性的从集群中的每个DataNode接收心跳信合和状态报告,接收到心跳信号意味着DataNode节点工作正常,块状态报告包含了一个该DataNode上所有的数据列表
2.6 一次写入,多次读出
HDFS 是设计成适应一次写入,多次读出的场景,且不支持文件的修改。
正因为如此,HDFS 适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
3.NameNode与Datanode的总结概述
3.1namenode 元数据管理
我们把目录结构及文件分块位置信息叫做元数据。Namenode 负责维护整个hdfs文件系统的目录树结构,以及每一个文件所对应的 block 块信息(block 的id,及所在的datanode 服务器)。
3.2 Datanode 数据存储
文件的各个 block 的具体存储管理由 datanode 节点承担。每一个 block 都可以在多个datanode 上。Datanode 需要定时向 Namenode 汇报自己持有的 block信息。 存储多个副本(副本数量也可以通过参数设置 dfs.replication,默认是 3)。
4.文件副本机制以及block块存储
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yW1xc94c-1636706490703)(day02_hadoop.assets/1626363979672.png)]
所有的文件都是以block块的方式存放在HDFS文件系统当中,在hadoop1当中,文件的block块默认大小是64M,hadoop2当中,文件的block块大小默认是128M,block块的大小可以通过hdfs-site.xml当中的配置文件进行指定
5.元文件FSImage与edits
FSimage是一个镜像文件,是一个完整的元数据文件
edits是每隔一个小时生成
客户端对hdfs进行写文件时会首先被记录在edits文件中。
edits修改时元数据也会更新。
每次hdfs更新时edits先更新后客户端才会看到最新信息。
fsimage:是namenode中关于元数据的镜像,一般称为@检查点。
一般开始时对namenode的操作都放在edits中,为什么不放在fsimage中呢?
因为fsimage是namenode的完整的镜像,内容很大,如果每次都加载到内存的话生成树状拓扑结构,这是非常耗内存和CPU。
fsimage内容包含了namenode管理下的所有datanode中文件及文件block及block所在的datanode的元数据信息。随着edits内容增大,就需要在一定时间点和fsimage合并。
2.x的hadoop元数据合并条件
dfs.namenode.checkpoint.period: 默认是一个小时(3600s)
dfs.namenode.checkpoint.txns:默认为1000000条edits记录
FSimage文件当中的文件信息查看:
cd /opt/servers/hadoop-2.7.7/tmp/dfs/name/current
hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml
edits当中的文件信息查看:
cd /opt/servers/hadoop-2.7.7/tmp/dfs/nn/edits
hdfs oev -i edits_0000000000000000865-0000000000000000866 -o myedit.xml -p XML
6、HDFS的文件写入过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XoRsTpwR-1636706490705)(day02_hadoop.assets/a.png)]
详细步骤解析:
1、 client发起文件上传请求,通过RPC与NameNode建立通讯,NameNode检查目标文件是否已存在,父目录是否存在,返回是否可以上传;
2、 client请求第一个block该传输到哪些DataNode服务器上;
3、 NameNode根据配置文件中指定的备份数量及机架感知原理进行文件分配,返回可用的DataNode的地址如:A,B,C;
注:Hadoop在设计时考虑到数据的安全与高效,数据文件默认在HDFS上存放三份,存储策略为本地一份,同机架内其它某一节点上一份,不同机架的某一节点上一份。
4、 client请求3台DataNode中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成,后逐级返回client;
5、 client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(默认64K),A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答。
6、 数据被分割成一个个packet数据包在pipeline上依次传输,在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipelineack发送给client;
7、 当一个block传输完成之后,client再次请求NameNode上传第二个block到服务器。
7、HDFS的文件读取过程
详细步骤解析
1、 Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
2、 NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode 都会返回含有该 block 副本的 DataNode 地址; 这些返回的 DN 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离 Client 近的排靠前;心跳机制中超时汇报的 DN 状态为 STALE,这样的排靠后;
3、 Client 选取排序靠前的 DataNode 来读取 block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);
4、 底层上本质是建立 Socket Stream(FSDataInputStream),重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕;
5、 当读完列表的 block 后,若文件读取还没有结束,客户端会继续向NameNode 获取下一批的 block 列表;
6、 读取完一个 block 都会进行 checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的DataNode 继续读。
7、 read 方法是并行的读取 block 信息,不是一块一块的读取;NameNode 只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
8、 最终读取来所有的 block 会合并成一个完整的最终文件。
8.HDFS基本Shell操作
创建文件夹(支持多级创建):
hadoop fs -mkdir -p /xxx
查看目录:
hadoop fs -ls /xxx
递归查看多级目录:
hadoop fs -lsr /xxx
上传文件到HDFS:
hadoop fs -put xxx.txt /xxx
下载文件到本地当前目录:
hadoop fs -get /xxx/xxx/xxx.txt
删除文件:
hadoop fs -rm /xxx/xxx/xxx.txt
删除文件夹(文件夹必须为空):
hadoop fs -rmdir /xxx/xxx
强制删除文件夹或文件
Hadoop fs -rm -r /xxx
9.HDFS的api操作
9.1前期准备
1.解决winutils.exe的问题
1)把hadoop2.7.7(windows版)文件目录放到一个没有中文没有空格的路径下
2)在window中配置handoop的环境变量,并且加入path中。
9.2 创建maven工程并导入jar包
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.7</version>
</dependency>
9.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 , 默 认 值 为 : file:/// , 则 获 取 的 将 不 是 一 个DistributedFileSystem 的实例,而是一个本地文件系统的客户端对象
9.3获取FileSystem的方式
Configuration configuration=new Configuration();
configuration.set("fs.defaultFS","hdfs://192.168.65.101:8020");
FileSystem fileSystem=FileSystem.get(configuration);
System.out.println(fileSystem.toString());
9.4创建文件夹
@Test
public void mkdirs() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.65.101:8020"), new Configuration());
boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));
fileSystem.close();
}
9.4下载文件
@Test
public void getFileToLocal()throws Exception{
Configuration configuration=new Configuration();
configuration.set("fs.defaultFS","hdfs://192.168.65.101:8020");
FileSystem fileSystem=FileSystem.get(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();
}
9.5上传文件
@Test
public void putData() throws Exception{
Configuration configuration=new Configuration();
configuration.set("fs.defaultFS","hdfs://192.168.65.101:8020");
FileSystem fileSystem=FileSystem.get(configuration);
fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));
fileSystem.close();
}