细的不能再细的HDFS客户端写数据流程(图+流程)

step1:client ----> NN
        客户端(你可以理解为shell命令行、java上调用API等等)调用抽象类FileSystem的get( )获取一个DistributedFileSystem对象, 然后调用DistributedFileSystem的create()方法该方法在底层会调用clientProtocol.create()方法,发起对namenode的RPC连接(不懂RPC不要紧,只要知道客户端调用分布式服务器,往往就是RPC连接,RPC是远程遥控框架,你可以理解为客户端是遥控器,服务端是空调),通知namenode在HDFS文件系统中创建一个新的空文件。

step2: NN----> client
        NameNode要执行各种检测,确保要创建的文件不存在、登录用户合法、是否具有写权限,满足要求时namenode会创建一个标记文件(在edits中),返回允许上传。否则返回一个IOException表示创建失败。

step3:client----> NN
        接收到响应后,DistributedFileSystem的create()就会返回一个HdfsDataOutputStream对象,这个对象底层封装了一个DFSOutputStream对象,给客户端用于写数据。然后DFSOutputStream会调用ClientProtocol.addBlock()方法向Namenode申请一个块

step4: NN-----> client (机架感知,副本数默认为3,所以返回3个 )      
        上面方法会返回一个LocatedBlock对象,包含了存储这个块的节点信息dn1,dn2,dn3地址列表。

step5: client----> dn1
        客户端根据拓扑距离最近原则联系dn1,请求上传数据,

step6: dn3---> dn2
       dn2---> dn3
        dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个pipeline建立完成。
        ---为啥采用串行写,而不是并行写?减轻client压力。

step7:  dn3 ---->dn2
        dn2---->dn1
        dn1---->client
        dn3、dn2、dn1通过pipeline逐级应答client。

step8: client ---> dn1
       dn1 ---> dn2
       dn2 ---> dn3
       客户端调用DFSOutputStream.write()方法写数据,写入的数据会先缓存在这个流中,数据被切分为64kB 一个的packet,packet由chunk组成,每个chunk由512B的数据和4B的校验和。当client端填充完currentPacket后,会把它放入DataStreamer的dataQueue队列中。DataStreamer是一个线程,它会从dataQueue中轮询取出packet,并将它发送到pipeline管道中的第一个datanode,同时将其从dataQueue移动到ackQueue。ResponseProcessor接收来自datanode的ack。当从所有datanode接收到一个成功的数据包时,ResponseProcessor从ackQueue中删除相应的数据包。如果某个datanode出现故障,所有没完成确认的数据包都从ackQueue中回退到dataque。DFSOutpurStream会调用updateBlockForpipelie()方法为数据块申请一个新的时间戳,然后使用这个新时间戳重新建立pipeline。这种机制保证了故障节点与新的管道节点在Namenode中的元数据上的时间戳不一致,旧节点上的数据会在后续管理中被删去。然后输出流会调用ClientProtocol.getAdditionalDataNode()方法要求nn分配一个新补充的datanode节点,然后使用新的时间戳建立管线,同时客户端会通知DataTransferProtocal通知管线上的一个DataNode复制新数据到这个节点上来。管线建立完毕后,输出流调用ClientProtocol.updatePipeline()更新namenode中的数据,实现从故障中恢复,客户端就可以进行正常的写操作了。
        
step9:  每成功接收一个块,DataNode就会通过调用DataNodeProtocol.blockReceiveAndDeketed()方法向Namenode汇报,NameNode会更新内存中的元数据。

step 10:当客户端调用close()方法关闭流时,输出流中剩余的没写入数据保持传输到DataNode,最终输出完毕后,输出流会调用ClientProtcol.complete()方法通知nnm结束。完毕后,,完。此时Namenode才将文件创建操作提交到日志里进行存储。

 

 

 

图参考《Hadoop2.x,源码》,绝大多数细节是通过查询hadoop 2.7.2 版本的源码得出。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值