好程序员大数据学习路线分享分布式文件系统HDFS,设计目标:

1存储量大

2自动快速检测应对硬件错误

3流式访问数据

4移动计算比移动数据本身更划算

5简单一致性模型

6异构平台可移植

特点

优点:

  1. 高可靠性:Hadoop按位存储和处理数据的能力强

  2. 高扩展性:hadoop是在可用的计算机集簇间分配数据并完成计算任务的,这些集簇可以方便地扩展到数以千计的节点中

  3. 高效性:hadoop能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此处理速度非常快

  4. 高容错性:hadoop能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配。

缺点:

  1. 不适合低延迟数据访问

  2. 无法高效存储大量小文件(每个文件存储都有属于自己的索引,元数据庞大就不高效)

  3. 不支持多用户写入及任意修改文件(可以删除以及追加,只是不能修改文件中某处的数据)

重要特性:

  1. 文件在物理上是分块存储,块的大小可以通过配置参数(dfs.blocksize)来规定,默认2.x版本之后是128M,老版本是64M

  2. HDFS会给哭护短提供一个统一的抽象目录树,客户端通过路径来访问文件,刑辱:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data

  3. 目录结构及文件分块信息(元数据)的管理由namenode承担—namenodeHDFS集群主节点,负责维护整个hdfs文件系统的目录树,以及每一个路径(文件)所对应的block块信息(blockid以及所在datanode服务器)

  4. 文件的各个block的存储管理由datanode承担—datanodeHDFS集群从节点,每一个block都可以在多个datanode上存储多个副本(副本参数设置dfs.replication)

  5. HDFS是设计成适应一次写入,多次读出的场景,且不支持文件的修改

  6. 管理文件系统的命名空间(元数据:包含文件名称、大小、所属人、地址)

  7. 规定客户端访问文件规则

三个服务

Namenode
任务清单

a) 文件大小是否已经超载(超过集群的负载)

b) 是否已经存在相同的文件

c) 是否具有创建该文件的权限

  1. 对文件执行命令,关闭,打开文件或者打开路径等操作

  2. 所有的数据节点发送心跳给NameNode,他需要确保数据节点DataNode是否在线,一个数据块报告包含所有这个数据节点上的所有block的状况

  3. 首先将fsimage(镜像)载入内存,并读取执行日志editlog的各项操作

  4. 一旦在内存中建立文件系统元数据映射,则创建一个新的fsimage文件(这个过程不需要secondaryNamenode)和一个空的editlog

  5. 在安全模式下,各个datanode会向namenode发送块列表的最新情况

  6. 此刻namenode运行在安全模式。即NameNode的文件系统对于客户端来说是只读

  7. NameNode开始监听RPCHTTP请求

启动过程

RPC:Remote Procedure Call Protocol---远程过程通过协议

它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议

  1. 系统中数据块的位置并不是由namenode维护的,而是以块列表形式存储在datanode

  2. 在系统的正常操作期间,namenode会在内存中保留所有块信息的映射信息

  3. fsimage:元数据镜像文件(保存文件系统的目录树)

  4. edit.log:元数据操作日志(针对目录树的修改操作)

两个重要文件
元数据镜像

a) 内存中保存一份最新的

b) 内存中镜像=fsimage+edits

SecondaryNamenode
工作任务

定期合并fsimageedits

c) Edits文件过大将导致NamenNode重启速度缓慢

d) SecondaryNameNode负责定期合并他们

 

Datanode


hdfs的写过程


写过程语言Description:
  1. Client通过调用FileSystemget方法与namenode进程建立通道进行通信,然后调用create方法来请求创建文件。

  2. FileSystem通过对namenode发出远程请求,在namenode里面创建一个新的文件,但此时并不关联任何的块。NameNode进行很多检查来保证不存在要创建的文件已经存在文件系统中,同时检查是否有相应的权限来创建文件。如果这些检查完了,nameNameNode将这个新文件的嘻嘻记录下来,然后FileSystem返回一个DFSOutputStream给客户端用来写入数据。和读的情形一样,FSDataOutputStream将包装一个DFSOutputStream用于和DataNodeNameNode通信。而一旦文件创建失败,客户端会受到一个IOException,标识文件创建失败,停止后续任务。

  3. 客户端开始写数。FSDataOutputStream把要写入的数据分成块打成包的形式,将其写入到DFSOutputStream对象的中间队列中。其中的数据由Datastreamer来读取。DataStreamer的职责是让NameNode分配新的块找出合适的DataNode来存储作为备份而复制的数据。

  4. FSDataOutputStream维护了一个内部关于packets的队列,里面存放等待被DataNode确认无误的packets的信息。这个队列被称为等待队列,一个packet的信息被移出本队列当且仅当packet被所有节点都确认无误。

  5. 当完成数据写入之后客户端调用流的close方法,再通知NameNode完成写入之前,这个方法将flush残留的packets,并等待确认信息。NameNode已经知道文件由哪些块组成,所以在返回成功前只需要等待数据块进行最小复制。

Write API:
1.从本地系统上传到hdfs

Configuration hdfsConf = new Configuration();//创建一个hdfs的环境变量

String namenodeURI=”hdfs://hadoop001:8020”;//namenode的统一资源定位符

String username=”root”;//访问指定用户的hdfs

FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);//创建一个hdfs的文件系统对象

FileSystem local = FileSystem.getLocal(new Configuration());//创建一个本地的文件系统对象

hdfs.copyFromLocalFile(new Path(localPath),new Path(hdfsPath));

2.hdfs上创建文件并直接给定文件的内容

FSDateOutputStream out = hdfs.create(new Path(hdfsPath));

out.write(fileContent.getBytes());

out.close();

hdfs的读过程


读过程语言Description:
  1. 客户端或者用户通过调用FileSystem对象的open方法打开需要读取的文件,这对HDFS来说是常见一个分布式文件系统的一个读取实例。

  2. FileSystem通过远程协议调用NameNode确定文件的前几个Block的位置。对于每一个BlockNamenode返回含有那个Block 的“元数据”,即文件基本信息;接下来,DataNode按照上文定义的距离来进行排序,如果Client本身就是一个DataNode优先从本地DataNode读物数据。HDFS实例完成以上工作后,返回一个FSDataInputStream给客户端,让其从FSDataInputStream中读取数据。FSDataInputStream接着包装一个DFSInputStream用来管理DataNodeNameNodeI/O

  3. NameNode向客户端返回一个包含数据信息的地址,客户端格努诋毁创建一个FSDataInputStream开始对数据进行读取。

  4. FSDataInputStream根据开始存放的前几个BlocksDataNode的地址,连接到最近的DataNode上对数据开始从头读取。客户端反复调用read()方法,以流式方式从DataNode读取数据

  5. 当读到Block的结尾的时候,FSDataInputStream会关闭当前DataNode的地址,然后查找能够读取下一个Block的最好的DataNode。这些操作对客户端是透明的,客户端感觉到的是连续的流,也就是说读取的时候就开始查找下一个块所在的地址。

  6. 读取完成调用close()方法,关闭FSDataInputStream

Read API:
1.hdfs上下载文件到本地

Configuration hdfsConf = new Configuration();//创建一个hdfs的环境变量

String namenodeURI=”hdfs://hadoop001:8020”;//namenode的统一资源定位符

String username=”root”;//访问指定用户的hdfs

FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);//创建一个hdfs的文件系统对象

FileSystem local = FileSystem.getLocal(new Configuration());//创建一个本地的文件系统对象

hdfs.copyToLocalFile(new Path(hdfsPath),new Path(localPath));

3. hdfs上读取给定文件的内容

Path path = new Path(hdfsFilePath);//文件路径

FSDataInputStream in = hdfs.open(path);//获取文件输入流

FileStatus status = hdfs.getFileStatus(path);//获取文件的元数据信息

//获取文件元数据中的文件大小

byte[] bytes = new byte[Integer.pareInt(String.valueOf(status.getLen()))];

//将输入流中的全部内容一次性读取出来

in.readFully(0,bytes);

System.out.println(new String(bytes));//将读取的文件打印输出

in.close();

hdfs的整体过程