Hadoop--客户端读写hdfs数据

详细见hadoop面试整理一

1.HDFS写文件

在这里插入图片描述1. 客户端将文件写入本地磁盘的文件中

  1. 当临时文件大小达到一个Block大小时,HDFS Client 通知 NameNode,申请写入文件
  2. NameNode 在HDFS的文件系统中创建一个文件,并把该 Block ID 和要写入的 DataNode 的列表返回给客户端
  3. 客户端收到这些消息后,将临时文件写入 DataNodes
    1.客户端将文件内容写入第一个 DataNode(一般以 4kb 单位进行传输)。
    2.第一个 DataNode 接收后,将数据写入本地磁盘,同时也传输给第二个 DataNode。
    3.以此类推到最后一个 DataNode,数据在 DataNode 之间是通过 pipeline 的方式进行复制的。
    4.后面的 DataNode 接受完数据后,都会发送一个确认给前一个 DataNode,最终第一个 DataNode 返回确认给客户端。
    5.当客户端接收到整个 Block 的确认后,会向 NameNode 发送一个最终的确认信息。
    6.如果写入某个 DataNode 失败,数据会继续写入其他的 DataNode。然后 NameNode 会找另一个好的 DataNode 继续复制,以保证冗余性。
    7.每个Block 都会有一个校验码,并存放到独立的文件中,以便读的时候验证其完整性。
    5.文件写完后(客户端关闭),NameNode 提交文件(这时文件才可见,如果提交前,NameNode 挂掉,那文件也就丢失了。
    fsync:只保证数据的信息写到 NameNode 上,但并不保证数据已经被写道 DataNode 中)

2.HDFS读文件

在这里插入图片描述1.客户端向 NameNode 发送读取请求。
2.NameNode 返回文件的所有 Block 和这些 Block 所在的 DataNodes(包括复制节点)。
3.客户端直接从 DataNode 中读取数据,如果该 DataNode 读取失败(DataNode 失效或校验码不对),则从复制节点中读取(如果读取的数据就在本机,则直接读取,否则通过网络读取)。

在这里插入图片描述

1.读数据

(1)客户端通过调用FIleSystem对象的open()方法来打开希望读取的文件,对于hdfs来说,这个对象是分布式文件系统的一个实例。
(2)DistributedFileSystem通过使用PRC(远程方法调用)来调用namenode,以确定文件起始块的位置。对于每一个块,namenode返回存有该块副本的datanode的地址。此外,这些datanode根据他们与客户端的距离来排序(机架感应)。如果该客户端本身就是一个datanode(比如,在一个MapReduce任务中),并保存有相应数据块的一个副本时,该节点将从本地datanode中读取数据。
(3)DistributedFileSystem类返回一个FSDataInputStream对象(支持文件定位的输入流)给客户端读取数据。FSDataInput类转而封装DFSInputStream对象,该对象管理着datanode、namenode的I/O。接着,客户端对这个输入流调用read()方法。
(4)存储着文件起始块的datanode地址的DFSInputStream 随即连接距离最近的文件中第一个块所在的datanode。通过对数据流反复调用read()方法,可以将数据从datanode传输到客户端。
(5)到达块的末端时,DFSInputStream 会关闭与该datanode的连接,然后寻找下一个块的最佳datanode。客户端只需要读取连续的流,并且对于客户端都是透明的。客户端从流中读取数据时,块是按照打开DFSInputStream与datanode新建连接的顺序读取的。它根据需要询问namenode来检索下一批所需块的datanode的位置。
(6)一旦客户端读取完成,就对FSDataInputStream调用close()方法,在读取数据的时候,如果DFSInputStream在与datanode通信时遇到错误,它便尝试从这个块的另外一个最邻近的datanode读取数据。它也会记住哪个故障的datanode,以保证以后不会反复读取该节点上后续的块。DFSInputStream也会通过校验和确认从datanode发来的数据是否完整。如果发现一个损坏的块,它就会在DFSInputStream 试图从其他datanode读取一个块的副本,也会将被损坏的块通知给namonode。

这个设计的一个重点是客户端可以直接连接到datanode检索数据,且namenode告诉客户端每个块中的最佳datanode。由于数据流分散在该集群中所有的datanode,所以这种设计能使HDFS可扩展到大量的并发客户端。同时,namenode仅需要响应快位置的请求(这些信息存储在内存中,因而非常高效),而无需响应数据请求,否则随着客户端数量的增长,namenode很快会成为一个瓶颈。
注:
(1)Remote Procdure call(RPC)远程方法调用,它允许一台计算机程序远程调用另外一台计算机的子程序,而不用去关心底层的网络通信细节,对我们来说是透明的。经常用于分布式网络通信中。
(2)Hadoop的进程间交互都死通过RPC来进行的,比如Namenode与Datanode直接,Jobtracker与Tasktracker之间等。

2.hadoop写:

在这里插入图片描述
(1)客户端通过对DistributeFileSystem 对象调用create()函数来创建文件
(2)DistributedFileSystem 对namenode创建一个RPC调用,在文件系统的命名空间中创建一个新文件,但是此时该文件中还没有相应的数据块,namenode执行各个不同的检查以确保这个文件不存在,并且客户端有创建该文件的权限。如果这些检查均通过,namenode就会为创建新文件记录一条记录,否则,文件创建失败并向客户端抛出一个IoException异常。
(3)DistributeFileSystem向客户端返回一个FSDataOutrputStream对象,由此客户端可以开始写入数据。就像读取事件一样,FSDataOutputStream封装一个DFSoutputstream对象,该对象负责处理datanode和namenode之间的通信。在客户端写入数据时,DFSoutputStream将它分成一个个的数据包,并写入内部队列,成为数据队列(data queue)
(4)dataStreamer处理数据队列,它的责任是根据datanode列表来要求namenode分配适合的新块来存储数据备份。这一组datanode构成一个管道(pip管道)—我们假设副本数是3,所以管道中有3个节点。dataStream将数据包流式传输到管道中第一个datanode,该datanode存储数据包之后,并将它发送到管道中第二个datanode中,同样操作,第二个datanode 将数据包存储后给第三个datanode。
(5)DFSOoutputStream也维护着一个内部数据包队列来等待datanode的收到确认回执,称为"确认队列"(ack queue)。当收到管道中所有的datanode确认信息后,该数据包才会从确认队列删除。

如果在数据写入期间,datanode发生故障,则执行以下操作,这对与写入数据的客户端是透明的。首先关闭管道确认把队列中的任何数据包都添回数据队列的最前端,以确保故障节点下游的datanode不会漏掉任何一个数据包。为存储在另一个正常datanode的当前数据块制定一个新的标识,并将该标识传送给namenode。以便故障datanode在恢复后可以删除存储的部分数据块。从管道中删除故障数据节点并且把余下的数据块写入管道中剩余的两个正常的datanode。namenode注意到块副本量不足时,会在另一个节点上创建一个新的副本。后续的数据块继续正常接受处理。
(6)客户端完成数据的写入后,会对数据流调用close()方法。
(7)该操作将剩余的所有数据包写入datanode管道中,并在联系namenode发送文件写入完成信号之前,等待确认。namenode已经知道文件由哪些块组成(通过DataStreamer询问数据块的分配),所以它在返回成功只需要等待数据块进行最小量的复制。

转载于:https://my.oschina.net/u/4009325/blog/2396167

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值