乐趣区

关于大数据:HDFS主要流程

HDFS 的几个典型的流程:客户端读 HDFS 文件流程、客户端写 HDFS 文件流程、客户端追加写 HDFS 文件流程、数据节点与名字节点交互流程以及 HDFS HA 切换流程等。

一、客户端读 HDFS 文件流程
  1. 关上 HDFS 文件:HDFS 客户端首先调用 DistributedFileSystem.open()办法关上 HDFS 文件,这个办法在底层会调用 ClientProtocol.open()办法,该办法会返回一个 HdfsDataInputStream 对象用于读取数据块。HdfsDataInputStream 其实是一个 DFSInputStream 的装璜类,真正进行数据块读取操作的是 DFSInputStream 对象。
  2. 从 Namenode 获取 Datanode 地址: 在 DFSInputStream 的构造方法中,会调用 ClientProtocol.getBlockLocations()办法向名字节点获取该 HDFS 文件起始地位数据块的地位信息。Namenode 返回的数据块的存储地位是依照与客户端的间隔远近排序的,所以 DFSInputStream 能够抉择一个最优的 Datanode 节点,而后与这个节点建设数据连贯读取数据块。
  3. 连贯到 Datanode 读取数据块:HDFS 客户端通过调用 DFSInputStream.read()办法从这个最优的 Datanode 读取数据块,数据会以数据包 (packet) 为单位从数据节点通过流式接口传送到客户端。当达到一个数据块的开端时,DFSInputStream 就会再次调用 ClientProtocol.getBlockLocations()获取文件下一个数据块的地位信息,并建设和这个新的数据块的最优节点之间的连贯,而后 HDFS 客户端就能够持续读取数据块了。
  4. 敞开输出流: 当客户端胜利实现文件读取后,会通过 HdfsDataInputStream.close()办法敞开输出流。

流程图如下:

客户端读取数据块时,很有可能存储这个数据块的数据节点出现异常,也就是无奈读取数据。呈现这种状况时,DFSInputStream 会切换到另一个保留了这个数据块正本的数据节点而后读取数据。同时须要留神的是,数据块的应答包中不仅蕴含了数据,还蕴含了校验值。HDFS 客户端接管到数据应答包时,会对数据进行校验,如果呈现校验谬误,也就是数据节点上的这个数据块正本呈现了损坏,HDFS 客户端就会通过 ClientProtocol.reportBadBlocks()向 Namenode 汇报这个损坏的数据块正本,同时 DFSInputStream 会尝试从其余的数据节点读取这个数据块。

二、客户端写 HDFS 文件流程
  1. 创立文件: HDFS 客户端写 - 一个 新的文件时, 会首先调用 DistributedFileSystem.create()办法在 HDFS 文件系统中创立一个新的空文件。这个办法在底层会通过调用 ClientProtocol.create()办法告诉 Namenode 执行对应的操作, Namenode 会首先在文件系统目录树中的指定门路下增加一个新的文件,而后将创立新文件的操作记录到 editlog 中。实现 ClientProtocol.create()调用后, DistributedFileSystem.create()办法就会返回一个 HdfsDataOutputStream 对象, 这个对象在底层包装了一个 DFSOutputStream 对象,真正执行写数据操作的其实是 DFSOutputStream 对象。
  2. 建设数据流管道: 获取了 DFSOutputStream 对象后,HDFS 客户端就能够调用 DFSOutputStream.write()办法来写数据了。因为 DistributedFileSystem.create()办法只是在文件系统目录树中创立了一个空文件,并没有申请任何数据块,所以 DFSOutputStream 会首先调用 ClientProtocol.addBlock()向 Namenode 申请一个新的空数据块,addBlock()办法会返回一个 LocatedBlock 对象,这个对象保留了存储这个数据块的所有数据节点的地位信息。取得了数据流管道中所有数据节点的信息后,DFSOutputStream 就能够建设数据流管道写数据块了。
  3. 通过数据流管道写入数据: 胜利地建设数据流管道后,HDFS 客户端就能够向数据流管道写数据了。写入 DFSOutputStream 中的数据会先被缓存在数据流中,之后这些数据会被切分成一个个数据包 (packet) 通过数据流管道发送到所有数据节点。通过数据流管道顺次写入数据节点的本地存储。每个数据包都有个确认包 (ack),确认包会逆序通过数据流管道回到输入流。输入流在确认了所有数据节点曾经写入这个数据包之后,就会从对应的缓存队列删除这个数据包。当客户端写满一个数据块之后,会调用 addBlock() 申请一个新的数据块,而后循环执行上述操作。
  4. 敞开输出流并提交文件: 当 HDFS 客户端实现了整个文件中所有数据块的写操作之后,就能够调用 close()办法敞开输入流,并调用 ClientProtocol.complete()办法告诉 Namenode 提交这个文件中的所有数据块,也就实现了整个文件的写入流程。

流程图如下:

对于 Datanode,当 Datanode 胜利地承受一个新的数据块时,Datanode 会通过
DatanodeProtocol.blockReceivedAndDeleted() 办法向 Namenode 汇报,Namenode 会更新内存中的数据块与数据节点的对应关系。

如果客户端在写文件时,数据流管道中的数据节点呈现故障,则输入流会进行如下操作来进行故障复原。

  1. 输入流中缓存的没有确认的数据包会重新加入发送队列,这种机制确保了数据节点呈现故障时不会失落任何数据,所有的数据都是通过确认的。输入流会通过调用 ClientProtocol.updateBlockForPipeline()办法为数据块申请一个新的工夫戳,而后应用这个新的工夫戳从新建设数据流管道。这种机制保障了故障 Datanode 上的数据块的工夫戳会过期,而后在故障复原之后,因为数据块的工夫戳与 Namenode 元数据中的不匹配而被删除,保障了集群中所有数据块的正确性。
  2. 故障数据节点会从输出流管道中删除,而后输入流会通过调用 ClientProtocol.getAdditionalDatanode()办法告诉 Namenode 调配新的数据节点到数据流管道中。接下来输入流会将新调配的 Datanode 增加到数据流管道中,并应用新的工夫戳从新建设数据流管道。因为新增加的数据节点上并没有存储这个新的数据块,这时 HDFS 客户端会通过 DataTransferProtocol 告诉数据流管道中的一个 Datanode 复制这个数据块到新的 Datanode 上.
  3. 数据流管道从新建设之后,输入流会调用 ClientProtocol.updatePipeline()更新 Namenode 中的元数据。至此,一个残缺的故障复原流程就实现了,客户端能够失常实现后续的写操作了。
三、Datanode 启动、心跳以及执行名字节点指令流程

Datanode 启动后与 Namenode 的交互次要包含三个局部:①握手;②注册;③块汇报以 及缓存汇报。

  1. Datanode 启动时会首先通过 DatanodeProtocol.versionRequest()获取 Namenode 的版本号以及存储信息等,而后 Datanode 会对 Namenode 的以后软件版本号和 Datanode 的以后软件、版本号进行比拟,确保它们是统一的。
  2. 胜利地实现握手操作后,Datanode 会通过 DatanodeProtocol.register()办法向 Namenode 注册。Namenode 接管到注册申请后,会判断以后 Datanode 的配置是否属于这个集群,它们之间的版本号是否统一。
  3. 注册胜利之后,Datanode 就须要将本地存储的所有数据块以及缓存的数据块上报到 Namenode,Namenode 会利用这些信息从新建设内存中数据块与 Datanode 之间的对应关系。

至此,Datanode 就实现了启动的所有操作,之后就能够失常对外服务了。

Datanode 胜利启动之后, 须要定期向 Namenode 发送心跳, 让 Namenode 晓得以后 Datanode 处于活动状态可能对外服务。Namenode 会在 Datanode 的心跳响应中携带名字节点指令,领导 Datanode 进行数据块的复制、删除以及复原等操作。

当 Datanode 胜利地增加了一个新的数据块或者删除了 - 一个已有的数据块时,须要通过 DatanodeProtocol.blockReceivedAndDeleted(办法向 Namenode 汇报。Namenode 接管到这个汇 报之后,会更新 Namenode 内存中数据块与数据节点之间的对应关系。

退出移动版