第三章、Hadoop之HDFS的读写与操作

一、HDFS的读数据流程

  • 补充一个问题
    当我们 NameNode 挂掉,SecondaryNameNode作为新的NameNode上位时,它确实可以根据fsimage.ckpt把一部分元数据加载到内存,可是如果这时还有一部分操作日志在edits new中没有执行怎么办?
  • 解决方案
    其中一个解决方案就是利用一个network fileSystem来解决,比如说集群中有一个服务器安装了一个nfs server,而在NameNode上再安装一个nfs client,此时客户端向HDFS写数据时,同时把向edits new中写的数据写一份到nfs server中,SecondaryNamenode就可以通过这个nfs server来获取此时断层的数据了
1、HDFS读取数据流程示意图

在这里插入图片描述

2、读取数据流程
  • 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
  • 挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
  • DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
  • 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
    步骤分析
3、详细读取数据流程步骤分析
  • HDFS client调用文件系统的open方法

  • Distributed FileSystem顾名思义是一个分布式文件系统,它会通过RPC的方式远程过程调用NameNode里的open方法。

  • Open方法作用: 就是获取要读的文件的file block locations,也就是文件的block的位置,我们知道一个文件是会分割成128M一块的大小,分别存储在各个数据节点的。

  • 同时在执行open方法时,客户端会产生一个FSData InputStream的一个输入流对象(客户端读数据是从外部读回来的)。

  • FSData InputStream读数据

  • HDFS client调用FSData InputStream的read方法,同上也是远程过程调用DataNode的read方法,此时的读取顺序是由近到远,就是DataNode和client node的距离,这里所指的距离是一种物理距离。

  • 在联系上DataNode并成功读取后,关闭流就走完了一个正常读取数据的流程。

  • 补充一下一点,上面Distributed FileSystem所调用的get block locations的方法只会返回部分数据块,get block locations会分批次地返回block块的位置信息。读block块理论上来说是依次读,当然也可以通过多线程的方式实现同步读。

  • 容错机制

  • 如果client从DataNode上读取block时网络中断了如何解决?
    此时我们会找到block另外的副本(一个block块有3个副本),并且通过FSData InputStream进行记录,以后就不再从中断的副本上读了。

  • 如果一个DataNode挂掉了怎么办? — A
    我们知道HDFS的心跳机制,DataNode会隔一小时向NameNode汇报blockReport,比如现在的情况是,block1的三个副本分别存储在DataNode1,2,3上,此时DataNode1挂掉了。NameNode得知某个block还剩2个副本,此时携带这block的其余两个副本的DataNode2,3在向NameNode报告时,NameNode就会对它们中的某一个返回一个指令,把block1复制一份给其他正常的节点。从而让block1恢复成原本的3个副本。

  • client如何保证读取数据的完整性?
    因为从DataNode上读数据是通过网络来读取的,这说明会存在读取过来的数据是不完整的或者是错误的情况。
    DataNode上存储的不仅仅是数据,数据还附带着一个叫做checkSum检验和(CRC32算法)的概念,针对于任何大小的数据块计算CRC32的值都是32位4个字节大小。此时我们的FSData InputStream向DataNode读数据时,会将与这份数据对应的checkSum也一并读取过来,此时FSData InputStream再对它读过来的数据做一个checkSum,把它与读过来的checkSum做一个对比,如果不一致,就重新从另外的DataNode上再次读取。

  • 上一个问题完成后工作
    FSData InputStream会告诉NameNode,这个DataNode上的这个block有问题了,NameNode收到消息后就会再通过心跳机制通知这个DataNode删除它的block块,然后再用类似上面标记A的做法,让正常的DataNode去copy一份正常的block数据给其它节点,保证副本数为3。

二、HDFS的写数据流程

1、HDFS写数据流程示意图

在这里插入图片描述

2、写数据流程

1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
2)NameNode返回是否可以上传。
3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
6)dn1、dn2、dn3逐级应答客户端。
7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。

3、详细写入数据流程步骤分析
  • 客户端调用分布式文件系统的create方法

  • 和上面读的方法类似,不过这次调用的是Distributed FileSystem的create方法,此时也是通过远程调用NameNode的create方法。
    此时NameNode会进行的举措:
    1)检测自己是否正常运行
    2)判断要创建的文件是否存在
    3)client是否有创建文件的权限
    4)对HDFS做状态的更改需要在edits log写日志记录

  • 客户端调用输出流的write方法

  • create方法的返回值是一个OutputStream对象,为什么是output,因为是由HDFS去往DataNode去写数据,此时HDFS会调用这个OutputStream的write方法。

  • 但是有个问题,此时我们还不知道我们的这些block块要分别存放于哪些节点上,所以此时FSData OutputStream就要再和NameNode交互一下,远程过程调用NameNode的addBlock方法,这个方法返回的是各个block块分别需要写在哪3个DataNode上面。此时OutputStream就完整得知了数据和数据该往哪里去写了。

  • 具体的写流程分析

  • 数据写入的时候会首先写入一个叫chunk块中,该chunk是一个512字节大小的数据块,写数据的过程中数据是一字节一字节往chunk那里写的,当写满一个chunk后,会计算一个checkSum,这个checkSum是4个字节大小,计算完成后一并放入chunk,所以整一个chunk大小其实是512字节+4字节=516字节。

  • 上述步骤结束后,一个chunk就会往package里面放,package是一个64kb大小的数据包,我们知道64kb = 64 * 1024字节,所以这个package可以放非常多的chunk。

  • 此时一个package满了之后,会把这个package放到一个data queue队列里面,之后会陆续有源源不断的package传输过来。

  • 这时候开始真正的写数据过程
    data queue中的package往数据节点DataNode上传输,传输的顺序按照NameNode的addBlock()方法返回的列表依次传输(ps:传输的类为一个叫做dataStreamer的类,而且其中addBlock方法返回的列表基本是按照离客户端物理距离由近到远的顺序的),往DataNode上传输的同时也往确认队列ack queue上传输针对DataNode中传输完成的数据做一个checkSum,并与原本打包前的checkSum做一个比较校验成功,就从确认队列ack queue中删除该package,否则该package重新置入data queue重传。

  • 补充:

  1. 以上逻辑归属于FSData OutputStream的逻辑。
  2. 虽然本身一个block为128M,而package为64Kb,128M对于网络传输过程来说算是比较大,拆分为小包是为了可靠传输。
  3. 网络中断时的举措:HDFS会先把整个pineline关闭,然后获取一个已存在的完整的文件的version,发送给NameNode后,由NameNode通过心跳机制对未正确传输的数据下达删除命令
  4. 如果是某个DataNode不可用,通过心跳机制会通知其余的可用DataNode的其中一个进行copy到一个可用节点上
  • 写入结束后的行动
  • 完成后通过心跳机制NameNode就可以得知副本已经创建完成,再调用addBlock()方法写之后的文件。
  • 流程总结
  1. client端调用Distributed FileSystem的create,此时是远程调用了NameNode的create,此时NameNode进行4个操作,检测自己是否正常,文件是否存在,客户端的权限和写日志。
  2. create的返回值为一个FSData OutputStream对象,此时client调用流的write方法,和NameNode进行连接,NameNode的addBlock方法返回块分配的DataNode列表。
  3. 开始写数据,先写在chunk,后package,置入data queue,此时两个操作,向DataNode传输,和放入ack queue,DataNode传输结束会检测checkSum,成功就删除ack queue的package,否则放回data queue重传。
  4. 结束后关闭流,告诉NameNode,调用complete方法结束。

对以前的知识回顾,加深基础知识!
学习来自:尚硅谷大数据学习视频
每天进步一点点,也许某一天你也会变得那么渺小!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值