【精】彻底吃透HDFS写流程(3)-- DataStreamer线程和输出流write方法简要分析

有关HDFS写流程的系列文章:
【精】彻底吃透HDFS写流程(1)–BlockConstructionStage
【精】彻底吃透HDFS写流程(2)-- Namenode侧create文件
【精】彻底吃透HDFS写流程(3)-- DataStreamer线程和输出流write方法简要分析
【精】彻底吃透HDFS写流程(4)-- 输出流DFSOutputStream#write方法分析
【精】彻底吃透HDFS写流程(5)-- DataStreamer线程类run方法分析以及如何构建pipeline?
【精】彻底吃透HDFS写流程(6)-- addBlock RPC
【精】彻底吃透HDFS写流程(7)-- 客户端sendPacket以及相关输入输出流的对应关系
【精】彻底吃透HDFS写流程(8)-- 数据真正落盘

回顾一下前情提要:
在DFSClient#create中,调用了DFSOutputStream.newStreamForCreate创建DFSOutputStream输出流对象。newStreamForCreate方法里面做了很多事:

① 调用create RPC申请在Namenode侧创建一个文件,并返回一个HdfsFileStatus对象。
② 把第一步中返回的HdfsFileStatus对象传入DFSOutputStream构造函数中,构造一个DFSOutputStream对象。
③ 启动DFSOutputStream对象中的DataStreamer线程。

上一篇文章中我们讲完了在Namenode侧创建一个文件的元数据信息,并把它加入到文件系统目录树中,然后返回给客户端一个HdfsFileStatus对象,也就是上面的第①步。本文我们来介绍剩下的②③两步。

构造DFSOutputStream对象比较简单:

里面比较重要的一点是初始化了DataStreamer对象,DataStreamer本质上是个线程类,在构造完DFSOutputStream后,外层会调用它的start方法启动这个线程。


其实到这里,我们已经知道使用HDFS客户端API写文件时拿到输出流对象背后的全过程了。大家可以回顾一下,如果回想不起来,可以再看一下前面的系列文章加深印象。

那接下来如何继续分析写文件原理呢?其实有以下两个角度:
① 刚才说了DataStreamer是个线程,然后也start了。那我们看DataStreamer类的run方法不就结了么?
② 还可以通过HDFS API写文件的流程出发,拿到输出流out对象之后,要调用out的write方法写数据。那我们看write方法不也可以么?

接下来就分别从这两个角度出发做简要介绍。

一、DataStreamer#run

DataStreamer的功能:用来向处于pipeline中的datanode发送data packet(data packet其实就是数据)。每一个packet都有一个对应的序列号,当一个块的所有的packet都发送出去了,并且每一个packet都收到了datanode发回来的ack响应(这里的ack不是TCP里的那个ack,是HDFS中的叫法),那么DataStreamer就会关闭这个block。

DataStreamer类内部有两个比较重要的队列,一个是dataQueue,一个是ackQueue。DataStreamer线程从dataQueue中取出待发送的packet,把它发送给pipeline中的第一个datanode,并把这个packet从dataQueue中移除放入到ackQueue中。 DataStreamer里面的内部类ResponseProcessor线程类接收来自datanode的ack响应。接收到一个packet的成功的ack后,ResponseProcessor会把相应的packet从ackQueue中移除。

如果发生错误,所有未完成的packet将被移出ackQueue。通过从原始pipeline中剔除掉坏的datanode,建立一个新的pipeline。然后DataStreamer开始继续从dataQueue中取packet然后发送。

DataStreamer的run方法很长,里面的细节后面会开写的文章详细分析源码。

二、DFSOutputStream#write

如下图所示,可以看到DFSOutputStream类的write方法有两个常用的是继承自FSOutputSummer类。我们以第一个为例,去FSOutputSummer中看看。

FSOutputSummer类的write(byte b[], int off, int len)方法中使用FSOutputSummer#write1方法。直接看write1。


上图中writeChecksumChunks方法内部会去触发FSOutputSummer的子类DFSOutputStream的writeChunk方法。

此时是不是感觉通畅了?知道数据是怎么写入的了吧。

概括一下,就是你在用HDFS API中的输出流write数据时,底层会把你写入的数据以chunk为单位写入到DFSPacket对象的buf中。如果达到DFSPacket对象所允许的最大chunk数或者达到了hdfs block size(128M),则将此DFSPacket对象入队到dataQueue中。DataStreamer会从dataQueue中不断取packet发送到pipeline中的datanode上进行写入,并且有专门的线程处理Datanode写入packet数据成功的响应。

三、TODO

以后的文章都以精短为主,不写特别长篇大论的文章,因为那样会容易让看文章的人中途放弃,不如每篇文章讲一个小点效果好。

限于篇幅,后续会开新文章详细介绍本文中没有深入讲解的两个重要的东西:①DataStreamer#run方法的逻辑。
②DFSOutputStream#writeChunk方法的逻辑。
③Namenode侧选datanode的逻辑
③Datanode侧写入的逻辑(pipeline写入、选盘策略等)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叹了口丶气

觉得有收获就支持一下吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值