zoukankan      html  css  js  c++  java
  • 大数据系列2:Hdfs的读写操作

    在前文大数据系列1:一文初识Hdfs中,我们对Hdfs有了简单的认识。

    在本文中,我们将会简单的介绍一下Hdfs文件的读写流程,为后续追踪读写流程的源码做准备。


    Hdfs 架构

    首先来个Hdfs的架构图,图中中包含了Hdfs 的组成与一些操作。

    对于一个客户端而言,对于Hdfs的操作不外乎也就读写两个操作,接下来就去看看整个流程是怎么走的。

    下面我们由浅及深,分为简单流程,详细流程分别介绍读写过程


    简单流程

    读请求流程

    客户端需要读取数据的时候,流程大致如下:

    1. ClientNameNode发起读请求
    2. NameNode收到读请求后,会返回元数据,包括请求文件的数据块在DataNode的具体位置。
    3. Client根据返回的元数据信息,找到对应的DataNode发起读请求
    4. DataNode收到读请求后,会返回对应的Block数据给Client

    写请求流程

    客户端需要写入数据的时候,流程大致如下:

    1. ClientNameNode发起写请求,其中包含写入的文件名,大小等。
    2. NameNode接收到信息,NameNode会将文件的信息存储到本地,同时判断客户端的权限、以及文件是否存在等信息,验证通过后NameNode返回数据块可以存储的DataNode信息。
    3. 客户端会切割文件为多个Block,将每个Block写入DataNode,在DataNode之间通过管道,对Block做数据备份。

    详细流程

    读请求流程

    客户端需要读取数据的时候,流程大致如下:

    1. 客户端通过调用FileSystemopen()方法来读取文件。、
    2. 这个对象是DistributedFileSystem的一个实例,通过远程调用(RPC)与NameNode沟通,会向NameNode请求需要读写文件文件的Block位置信息。
    3. NameNode会进行合法性校验,然后返回Block位置信息,每一个Block都会返回存有该副本的DataNode地址,并且会根据DtaNode与Client的距离进行排序(这里的距离是指集群网络拓扑的距离,也是尽可能满足数据本地性的要求)
    4. DistributedFileSystem会返回一个支持文件定位的输入流FSDataInputStream给客户端,其中封装着DFSInputStream对象,该对象管理者DataNodeNameNode之间的I/O
    5. Client对这个输入流调用read()方法
    6. DFSInputStream存储了文件中前几个块的DataNode地址,然后在文件第一个Block所在的DataNode中连接最近的一个DtaNode。通过对数据流反复调用read(),可以将数据传输到客户端。
    7. 当到到Block的终点的时候,DFSInputStream会关闭与DataNode的链接。然后搜寻下一个BlockDataNode重复6、7步骤。在Client看来,整个过程就是一个连续读取过程。
    8. 当完成所有Block的读取后,Client会对FSDataInputStream调用close()

    Client 读取数据流的时候,Block是按照DFSInputStreamDataNode打开新的连接的顺序读取的。
    并且在有需要的时候,还会请求NameNode返回下一个批次BlocksDataNode信息

    DFSInputStreamDataNode交互的时候出现错误,它会尝试选择这个Block另一个最近的DataNode,并且标记之前的DataNode避免后续的Block继续在该DataNode上面出错。

    DFSInputStream也会对来自DataNode数据进行校验,一旦发现校验错误,也会从其他DataNode读取该Bclock的副本,并且向NamaNode上报Block错误信息。

    整个流程下来,我们可以发现Client直接连接到DataNode检索数据并且通过NameNode知道每个Block的最佳DataNode。

    这样设计有一个好处就是:

    因为数据流量分布在集群中的所有DataNode上,所以允许Hdfs扩展到大量并发Client.

    与此同时,NamaNode只需要响应Block的位置请求(这些请求存储在内存中,非常高效),
    而不需要提供数据。

    否则随着客户端数量的快速增加,NameNode会成为成为性能的瓶颈。


    读请求流程

    客户端需要写入数据的时候,流程大致如下:

    1. Client通过create()方法调用DistributedFileSystemcreate()
    2. DistributedFileSystem通过RPCNameNode请求建立在文件系统的明明空间中新建一个文件,此时只是建立了一个空的文件加,并没有Block
    3. NameNode接收到crete请求后,会进行合法性校验,比如是否已存在相同文件,Client是否有相关权限。如果校验通过,NameNode会为新文件创建一个记录,并返回一些可用的DataNode。否则客户端抛出一个IOException
    4. DistributedFileSystem 会返回一个FSDataOutputStream个Client,与读取数据类似,FSDataOutputStream封装了一个DFSOutputStream,负责NameNodeDataNode之间交互。
    5. Client调用write()
    6. DFSOutputStream会将数据切分为一个一个packets,并且将之放入一个内部队列(data queue),这个队列会被DataStreamer消费,DataStreamer通过选择一组合合适DataNodes来写入副本,并请求NameNode分配新的数据块。与此同时,DFSOutputStream还维护一个等待DataNode确认的内部包队列(ack queue)
    7. 这些DataNodes会被组成一个管道(假设备份数量为3)
    8. 一旦pipeline建立,DataStreamerdata queue中存储的packet流式传入管道的第一个DataNode,第一个DataNode存储Packet并将之转发到管道中的第二个DataNode,同理,从第二个DataNode转发到管道中的第三个DataNode
    9. 当所一个packet已经被管道中所有的DataNode确认后,该packet会从ack queue移除。
    10. Client完成数据写入,调用close(),此操作将所有剩余的数据包刷新到DataNode管道,等待NameNode返回文件写入完成的确认信息。
    11. NameNode已经知道文件是由哪个块组成的(因为是DataStreamer请求NameNode分配Block的),因此,它只需要等待Block被最小限度地复制,最后返回成功。

    如果在写入的过程中发生了错误,会采取以下的操作:

    1. 关闭管道,并将所有在ack queue中的packets加到 data queue的前面,避免故障节点下游的DataNode发生数据丢失。
    2. 给该Block正常DataNode一个新的标记,将之告知NameNode,以便后续故障节点在恢复后能删除已写入的部分数据。
    3. 将故障节点从管道中移除,剩下的两个正常DataNodes重新组成管道,剩余的数据写入正常的DataNodes
    4. NameNode发现备份不够的时候,它会在另一个DataNode上创建一个副本补全,随后该Blcok将被视为正常

    针对多个DataNode出现故障的情况,我们只要设置 dfs.NameNode.replication.min的副本数(默认为1),Block将跨集群异步复制,直到达到其目标复制因子( dfs.replication,默认为3)为止.


    通俗易懂的理解

    上面的读写过程可以做一个类比,

    NameNode 可以看做是一个仓库管理员;
    DataNode 可以看作是仓库;

    管理员负责管理商品,记录每个商品所在的仓库;
    仓库负责存储商品,同时定期向管理员上报自己仓库中存储的商品;
    此处的商品可以粗略的理解为我们的数据。

    管理员只能有一个,而仓库可以有多个。

    当我们需要出库的时候,得先去找管理员,在管理员处取得商品所在仓库的信息;
    我们拿着这个信息到对应仓库提取我们需要的货物。

    当我们需要入库的时候,也需要找管理员,核对权限后告诉我们那些仓库可以存储;
    我们根据管理员提供的仓库信息,将商品入库到对应的仓库。


    存在的问题

    上面是关于Hdfs读写流程介绍,虽然我分了简单和详细,但是实际的读写比这个过程复杂得多。

    比如如何切块?
    为何小于块大小的文件按照实际大小存储?
    备份是如何实现的?
    Block的结构等等。

    这些内容会在后续的源码部分详细解答。

    此外,有人也许发现了,前文大数据系列1:一文初识Hdfs中Hdfs架构的介绍和本文读写的流程的介绍中,存在一个问题。

    就是NameNode的单点故障问题。虽然之前有SecondaryNameNode 辅助NameNode合并fsiamgeedits,但是这个还是无法解决NameNode单点故障的问题。
    很多人听过HA(High Availability) 即高可用,误以为高可用就是SecondaryNameNode,其实并不是。

    在下一篇文章中会介绍Hdfs高可用的实现方式。

    想了解更多内容观影关注:【兔八哥杂谈】

  • 相关阅读:
    灵魂有香气的女子IOS版本APP,近期将考虑开放源代码
    PHP中$_SERVER获取当前页面的完整URL地址
    zabbix监控报错zabbix server is not running解决方法
    Linux重启inotify配置max_user_watches无效被恢复默认值8192的正确修改方法
    centos在yum install报错:Another app is currently holding the yum lock解决方法
    nginx去掉单个目录和多个目录PHP执行权限方法
    express搭建权限管理系统
    在express项目中使用formidable & multiparty实现文件上传
    vue生成图片验证码
    第0步:OracleRAC软件准备
  • 原文地址:https://www.cnblogs.com/lillcol/p/14331682.html
Copyright © 2011-2022 走看看