Hadoop之HDFS读写原理

1、HDFS基本概念java

HDFS全称是Hadoop Distributed System。HDFS是为以流的方式存取大文件而设计的。适用于几百MB,GB以及TB,并写一次读屡次的场合。而对于低延时数据访问、大量小文件、同时写和任意的文件修改,则并非十分适合。node

目前HDFS支持的使用接口除了Java的还有,Thrift、C、FUSE、WebDAV、HTTP等。HDFS是以block-sized chunk组织其文件内容的,默认的block大小为64MB,对于不足64MB的文件,其会占用一个block,但实际上不用占用实际硬盘上的64MB,这能够说是HDFS是在文件系统之上架设的一个中间层。之因此将默认的block大小设置为64MB这么大,是由于block-sized对于文件定位颇有帮助,同时大文件更使传输的时间远大于文件寻找的时间,这样能够最大化地减小文件定位的时间在整个文件获取总时间中的比例。数据库

 

2、HDFS设计原则缓存

HDFS是Google的GFS(Google File System)的开源实现。具备如下五个基本目标:安全

一、硬件错误是常态而不是错误。HDFS通常运行在普通的硬件上,因此硬件错误是一种很正常的状况。因此在HDFS中,错误的检测并快速自动恢复是HDFS的最核心的设计目标。网络

二、流式数据访问。运行在HDFS上的应用主要是以批量处理为主,而不是用户交互式事务,以流式数据读取为多。数据结构

三、大规模数据集。HDFS中典型的文件大小要达到GB或者是TB级。架构

四、简单一致性原则。HDFS的应用程序通常对文件的操做时一次写入、屡次读出的模式。文件一经建立、写入、关闭后,通常文件内容再发生改变。这种简单的一致性原则,使高吞吐量的数据访问成为可能。函数

五、数据就近原则。HDFS提供接口,以便应用程序将自身的执行代码移动到数据节点上来执行。采用这种方式的缘由主要是:移动计算比移动数据更加划算。相比与HDFS中的大数据/大文件,移动计算的代码相比与移动数据更加划算,采用这种方式能够提供宽带的利用率,增长系统吞吐量,减小网络的堵塞程度。oop

 

3、HDFS的体系结构

构成HDFS主要是Namenode(master)和一系列的Datanode(workers)。

Namenode是管理HDFS的目录树和相关的文件元数据,这些信息是以"namespaceimage"和"edit log"两个文件形式存放在本地磁盘,可是这些文件是在HDFS每次重启的时候从新构造出来的。

Datanode则是存取文件实际内容的节点,Datanodes会定时地将block的列表汇报给Namenode。

因为Namenode是元数据存放的节点,若是Namenode挂了那么HDFS就无法正常运行,所以通常使用将元数据持久存储在本地或远程的机器上,或者使用secondary namenode来按期同步Namenode的元数据信息,secondary namenode有点相似于MySQL的Master/Salves中的Slave,"edit log"就相似"bin log"。若是Namenode出现了故障,通常会将原Namenode中持久化的元数据拷贝到secondary namenode中,使secondary namenode做为新的Namenode运行起来。

HDFS是一个主从结构(master/slave)。如图所示:

 技术分享

 

4、HDFS可靠性保障措施

HDFS的主要设计目标之一是在故障状况下,要保障数据存储的可靠性。

HDFS具有了完善的冗余备份和故障恢复机制。通常经过dfs.replication设置备份份数,默认3。

一、冗余备份。将数据写入到多个DataNode节点上,当其中某些节点宕机后,还能够从其余节点获取数据并复制到其余节点,使备份数达到设置值。dfs.replication设置备份数。

二、副本存放。HDFS采用机架感知(Rack-aware)的策略来改进数据的可靠性、可用性和网络宽带的利用率。当复制因子为3时,HDFS的副本存放策略是:第一个副本放到同一机架的另外一个节点(执行在集群中)/随机一个节点(执行在集群外)。第二个副本放到本地机架的其余任意节点。第三个副本放在其余机架的任意节点。这种策略能够防止整个机架失效时的数据丢失,也能够充分利用到机架内的高宽带特效。

三、心跳检测。NameNode会周期性的从集群中的每个DataNode上接收心跳包和块报告,NameNode根据这些报告验证映射和其余文件系统元数据。当NameNode无法接收到DataNode节点的心跳报告后,NameNode会将该DataNode标记为宕机,NameNode不会再给该DataNode节点发送任何IO操做。同时DataNode的宕机也可能致使数据的复制。通常引起从新复制副本有多重缘由:DataNode不可用、数据副本损坏、DataNode上的磁盘错误或者复制因子增大。

四、安全模式。在HDFS系统的时候,会先通过一个彻底模式,在这个模式中,是不容许数据块的写操做。NameNode会检测DataNode上的数据块副本数没有达到最小副本数,那么就会进入彻底模式,并开始副本的复制,只有当副本数大于最小副本数的时候,那么会自动的离开安全模式。DataNode节点有效比例:dfs.safemode.threshold.pct(默认0.999f),因此说当DataNode节点丢失达到1-0.999f后,会进入安全模式。

五、数据完整性检测。HDFS实现了对HDFS文件内容的校验和检测(CRC循环校验码),在写入数据文件的时候,也会将数据块的校验和写入到一个隐藏文件中()。当客户端获取文件后,它会检查从DataNode节点获取的数据库对应的校验和是否和隐藏文件中的校验和一致,若是不一致,那么客户端就会认为该数据库有损坏,将从其余DataNode节点上获取数据块,并报告NameNode节点该DataNode节点的数据块信息。

六、回收站。HDFS中删除的文件先会保存到一个文件夹中(/trash),方便数据的恢复。当删除的时间超过设置的时间阀后(默认6小时),HDFS会将数据块完全删除。

七、映像文件和事务日志。这两种数据是HDFS中的核心数据结构。

八、快照。

 

5、数据存储操做

1、数据存储: block

默认数据块大小为128MB,可配置。若文件大小不到128MB,则单独存成一个block。

为什么数据块如此之大?    数据传输时间超过寻道时间(高吞吐率)

一个文件存储方式?      按大小被切分红若干个block,存储到不一样节点上,默认状况下每一个block有三个副本。

2、数据存储: staging

HDFSclient上传数据到HDFS时,首先,在本地缓存数据,当数据达到一个block大小时,请求NameNode分配一个block。 NameNode会把block所在的DataNode的地址告诉HDFS client。 HDFS client会直接和DataNode通讯,把数据写到DataNode节点一个block文件中。

 

6、写入数据

1.初始化FileSystem,客户端调用create()来建立文件。

2.FileSystem用RPC调用元数据节点,在文件系统的命名空间中建立一个新的文件,元数据节点首先肯定文件原来不存在,而且客户端有建立文件的权限,而后建立新文件。

3.FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。

4.DFSOutputStream将数据分红块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。

5.DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。

6.当客户端结束写入数据,则调用stream的close函数。此操做将全部的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。

7.若是数据节点在写入的过程当中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后可以察觉其数据块是过期的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,未来会再建立第三份备份。

8.若是在写的过程当中某个datanode发生错误,会采起如下几步:

1)pipeline被关闭掉;

2)为了防止防止丢包ack quene里的packet会同步到data quene里;

3)把产生错误的datanode上当前在写但未完成的block删掉;

4)block剩下的部分被写到剩下的两个正常的datanode中;

5)namenode找到另外的datanode去建立这个块的复制。固然,这些操做对客户端来讲是无感知的。

 

Java代码

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path file = new Path("demo.txt");
FSDataOutputStream outStream =fs.create(file);
outStream.writeUTF("Welcome to HDFSJava API!!!");
outStream.close();

 

写入过程图片:

技术分享

 

7、读取过程

  1.初始化FileSystem,而后客户端(client)用FileSystem的open()函数打开文件。

2.FileSystem用RPC调用元数据节点,获得文件的数据块信息,对于每个数据块,元数据节点返回保存数据块的数据节点的地址。

3.FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。

4.DFSInputStream链接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端(client)

5.当此数据块读取完毕时,DFSInputStream关闭和此数据节点的链接,而后链接此文件下一个数据块的最近的数据节点。

6.当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。

7.在读取数据的过程当中,若是客户端在与数据节点通讯出现错误,则尝试链接包含此数据块的下一个数据节点。

8. 失败的数据节点将被记录,之后再也不链接。

 

Java代码

Configurationconf = new Configuration(); 
FileSystemfs = FileSystem.get(conf); 
Pathfile = new Path("demo.txt"); 
FSDataInputStreaminStream = fs.open(file); 
Stringdata = inStream.readUTF(); 
System.out.println(data); 
inStream.close();

 

读取文件过程图片:

技术分享

 

原文地址:http://jaydenwang.blog.51cto.com/6033165/1842812

相关文章
相关标签/搜索