HDFS读取原理

Introduction

HDFS开创性地设计出一套文件存储方式,即对文件分割后分别存放;HDFS将要存储的大文件进行分割,分割后存放在既定的存储块(Block )中,并通过预先设定的优化处理,模式对存储的数据进行预处理,从而解决了大文件储存与计算的需求;一个HDFS集群包括两大部分,即NameNodeDataNode。一般来说,一个集群中会有一个NameNode和多个DataNode共同工作;NameNode是集群的主服务器,主要是用于对HDFS中所有的文件及内容数据进行维护,并不断读取记录集群中DataNode主机情况与工作状态,并通过读取与写入镜像日志文件的方式进行存储;DataNodeHDFS集群中担任任务具体执行角色,是集群的工作节点。文件被分成若干个相同大小的数据块,分别存储在若干个DataNode上,DataNode会定期向集群内NameNode发送自己的运行状态与存储内容,并根据NameNode发送的指令进行工作;NameNode负责接受客户端发送过来的信息,然后将文件存储位置信息发送给提交请求的客户端,由客户端直接与DataNode进行联系,从而进行部分文件的运算与操作。BlockHDFS的基本存储单元,默认大小是64MHDFS还可以对已经存储的Block进行多副本备份,将每个Block至少复制到3个相互独立的硬件上,这样可以快速恢复损坏的数据;用户可以使用既定的API接口对HDFS中的文件进行操作;当客户端的读取操作发生错误的时候,客户端会向NameNode报告错误,并请求NameNode排除错误的DataNode后后重新根据距离排序,从而获得一个新的DataNode的读取路径。如果所有的DataNode都报告读取失败,那么整个任务就读取失败;对于写出操作过程中出现的问题,FSDataOutputStream并不会立即关闭。客户端向NameNode报告错误信息,并直接向提供备份的DataNode中写入数据。备份DataNode被升级为首选DataNode,并在其余2DataNode中备份复制数据。NameNode对错误的DataNode进行标记以便后续对其进行处理

Quick Start

HDFS基本命令

hadoop fs -cmd

cmd:具体的操作,基本上与UNIX的命令行相同

args:参数

HDFS资源URI格式:

scheme://authority/path

scheme:协议名,filehdfs

authority:namenode主机名

path:路径

示例:hdfs://localhost:9000/user/chunk/test.txt

假设已经在core-site.xml里配置了fs.default.name=hdfs://localhost:9000,则仅使用/user/chunk/test.txt即可。

hdfs默认工作目录为/user/$USER$USER是当前的登录用户名。

HDFS命令示例:

hadoop fs -mkdir /user/trunk

hadoop fs -ls /user

hadoop fs -lsr /user (递归的)

hadoop fs -put test.txt /user/trunk

hadoop fs -put test.txt . (复制到hdfs当前目录下,首先要创建当前目录)

hadoop fs -get /user/trunk/test.txt . (复制到本地当前目录下)

hadoop fs -cat /user/trunk/test.txt

hadoop fs -tail /user/trunk/test.txt (查看最后1000字节)

hadoop fs -rm /user/trunk/test.txt

hadoop fs -help ls (查看ls命令的帮助文档)

图中的2:文件备份数量,因为采用了两台机器的全分布模式,所以此处为2.对于目录,使用-

put的时候遇到问题:

Configuration

Read File

存储结构

行存储

HDFS块内行存储的例子:

基于Hadoop系统行存储结构的优点在于快速数据加载和动态负载的高适应能力,这是因为行存储保证了相同记录的所有域都在同一个集群节点,即同一个HDFS块。不过,行存储的缺点也是显而易见的,例如它不能支持快速查询处理,因为当查询仅仅针对多列表中的少数几列时,它不能跳过不必要的列读取;此 外,由于混合着不同数据值的列,行存储不易获得一个极高的压缩比,即空间利用率不易大幅提高。

列存储

HDFS上按照列组存储表格的例子。在这个例子中,列A和列B存储在同一列组,而列C和列D分别存储在单独的列组。查询时列存储能够避免读不必要的列,并且压缩一个列中的相似数据能够达到较高的压缩比。然而,由于元组重构的较高开销,它并不能提供基于Hadoop系统的快速查询处理。列存储不能保证同一 记录的所有域都存储在同一集群节点,行存储的例子中,记录的4个域存储在位于不同节点的3HDFS块中。因此,记录的重构将导致通过集群节点网络的大 量数据传输。尽管预先分组后,多个列在一起能够减少开销,但是对于高度动态的负载模式,它并不具备很好的适应性。

数据读取

hdfs读取数据流程图:

1、首先调用FileSystem对象的open方法,其实获取的是一个DistributedFileSystem的实例。2、DistributedFileSystem通过RPC(远程过程调用)获得文件的第一批blocklocations,同一block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。3、前两步会返回一个FSDataInputStream对象,该对象会被封装成DFSInputStream对象,DFSInputStream可以方便的管理datanodenamenode数据流。客户端调用read方 法,DFSInputStream就会找出离客户端最近的datanode并连接datanode。4、数据从datanode源源不断的流向客户端。5、如果第一个block块的数据读完了,就会关闭指向第一个block块的datanode连接,接着读取下一个block块。这些操作对客户端来说是透明的,从客户端的角度来看只是读一个持续不断的流。6、如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blockslocation,然后继续读,如果所有的block块都读完,这时就会关闭掉所有的流。

数据写入

hdfs写数据流程:

1.客户端通过调用DistributedFileSystemcreate方法,创建一个新的文件。2.DistributedFileSystem通过RPC(远程过程调用)调用NameNode,去创建一个没有blocks关联的新文件。创建前,NameNode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode就会记录下新文件,否则就会抛出IO异常。3.前两步结束后会返回FSDataOutputStream的对象,和读文件的时候相似,FSDataOutputStream被封装成DFSOutputStreamDFSOutputStream可以协调NameNodeDataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data queue4.DataStreamer会去处理接受data queue,它先问询NameNode这个新的block最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的DataNode,把它们排成一个pipelineDataStreamerpacket按队列输出到管道的第一个DataNode中,第一个DataNode又把packet输出到第二个DataNode中,以此类推。5.DFSOutputStream还有一个队列叫ack queue,也是由packet组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。6.客户端完成写数据后,调用close方法关闭写入流。7.DataStreamer把剩余的包都刷到pipeline里,然后等待ack信息,收到最后一个ack后,通知DataNode把文件标示为已完成。

NameNode HA

NameNode HA架构如下:

  • Active NameNodeStandby NameNode

两台NameNode形成互备,一台处于Active状态,为主NameNode,另外一台处于Standby状态,为备NameNode,只有主NameNode才能对外提供读写服务。

  • 主备切换控制器ZKFailoverController

    ZKFailoverController作为独立的进程运行,对NameNode的主备切换进行总体控制。ZKFailoverController能及时检测到NameNode的健康状况,在主NameNode故障时借助Zookeeper实现自动的主备选举和切换。

  • Zookeeper集群:

    为主备切换控制器提供主备选举支持。

  • 共享存储系统:

    共享存储系统是实现NameNode的高可用最为关键的部分,共享存储系统保存了NameNode在运行过程中所产生的HDFS的元数据。主NameNode和备用NameNode通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主NameNode在确认元数据完全同步之后才能继续对外提供服务。

上一页
下一页