上一篇说了datanode端如何处理pipeline写请求的,这里主要看DFSClient。

这里以append为例, write差不多。

创建一个pipeline用于append操作的流程:
FileSystem.get(configuration) 返回一个已经初始化完成的DistributedFileSystem对象,内部包含一个DFSClient对象

DistributedFileSystem.append(Path)内部调用DFSClient的append方法返回一个FSDataOutputStream(实际是HdfsDataOutputStream)
,应用往这个stream中write数据即可。

看看DFSClient.append()做了什么

  1. 调namenode.getFileInfo(file)向namenode得到file的相关信息,包括文件长度,
    mtime,atime,block_size,是否为目录,权限,owner,group等.

  2. 调namenode.append(file,clientName)获取file最后一个block的位置信息,以LocatedBlock形式返回.具体看看这个函数.

    2.1 namenode内部调用FSNameSystem的appendFile(file, clientName)
    从FSDirectory中拿到file对应的INode,做一些check,比如权限,file是文件,不是目录等。
    然后调用recoverLeaseInternal检查是否file需要recover lease,详细看看这个函数:
    从INodeFile可以知道这个文件是否处于under construction状态,如果不是,则说明不需要进 行lease recovery. 如果是,那么从LeaseManager拿到clientname对应的Lease,以及file所在的Lease,检查是否这个file的Lease已经被当前clientname持有,如果是,则抛异常,客户端append失败。否则,从INodeFile中拿到当前file的lease holder
    ,然后去LeaseManager中根据lease holder拿到Lease,然后判断Lease是否过期(lease最后更新时间离现在已经超过soft limit,默认60s)。如果没有过期,说明当前文件的lease正被别人持有,不能进行append,抛异常,客户端append失败.如果过期,开始
    进入lease recovery阶段, 执行internalReleaseLease(),函数的目的就是使这个file的最后一个block的所有副本数据一致,副本数据不一致可能由之前写这个文件的客户端意外宕机导致。这个问题后续专门分析。

    2.2 检查最后一个block是否副本数足够,如果不足够,同样抛异常,客户端失败。

    2.3 将INodeFile设置为under construction状态,将clientname作为lease holder设置到INodeFile中。同时将clientname,filename添加到Lease中。

    2.4 从INodeFile拿出最后一个block的BlockInfo,如果block已经满了,则返回null,后续客户端会发addBlock请求给namenode申请block进行append。如果block不满,将最后一个block设置为under construction状态。更新blocksMap.最后,将最后一个block的LocatedBlock返回给DFSClient.

  3. 构造DFSOutputStream对象,并且启动对象内部的DataStreamer线程,这里会根据上一步的LocatedBlock来设置DataStreamer的stage状态,显然,如果上一步返回的LocatedBlock不为空,说明append的最后一个block没有满,则stage设置为PIPELINE_SETUP_APPEND,isAppend设置为true,如果LocatedBlock为空,则stage设置为PIPELINE_SETUP_CREATE,isAppend设置false,在这种情况下,会调用nextBlockOutputStream函数来建立pipeline,内部会调用addBlock()向namenode申请一个新的block用于append。最后返回一个包装了DFSOutputStream的HdfsDataOutputStream的对象给客户端.

客户端拿到HdfsDataOutputStream后,往流里写数据,数据以packet的形式被放如DataStreamer
的dataQueue中。DataStreamer线程就是建立pipeline后,往pipeline中写一个个packet,最后关闭pipeline.

对于append来说,建立pipeline的函数是setupPipelineForAppendOrRecovery,函数内部会处理
建立pipeline过程中的失败和重试,最后函数的返回值就代表pipeline是否建立成功.

下面看setupPipelineForAppendOrRecovery是如何建立pipeline和建立失败时pipeline的重试工作.

DFSOutputStream中的DataStreamer建立pipeline时,如果出现某个坏的datanode,那么pipeline会断掉,例如client->A->B->C,B给C建立pipeline时,C是一个坏的datanode,那么在B的DataXceiver.writeBlock()中会设置BlockOpResponseProto的firstBadLink,然后回复给A,A收到后,主动断开和B的连接,以此类推。
pipeline建立失败会将这个第一个坏的datanode踢出pipeline并且放入到一个失败集合中.然后对剩下的datanode检查是否满足了replace-datanode policy,简单来说,就是检查是否需要新增一个datanode进来构成新的pipeline集合,是否需要增加新的datanode进来,主要考虑几个因素, 副本数,是否执行的hflush,是否append操作,当前pipeline中datanode个数.如果最后判定需要新增加datanode,会调用getAdditionalDatanode请求namenode重新分配一个datanode,这里会将失败集合发给namenode,namenode这次不会再选择这些坏的datanode.随后调updateBlockForPipeline向namenode重新申请这个block的新的generation stamp和token.然后调用createBlockOutputStream()重新建立pipeline.一旦建立pipeline成功,会调用updatePipeline向namenode更新pipeline,将旧block和新block的信息发给namenode,namenode根据旧block信息从BlockManager中找到对应的BlockInfo,确定其处于UNDER_CONSTRUCTION状态,并且从BlockInfo中拿出这个Block所在的HDFS文件对应的inode结构INodeFile,并且确定file处于under construction状态,并且确定从INodeFile拿出的clientname和传进来的clientname是相等的。然后,从INodeFile中取出最后一个BlockInfo,将其cast成BlockInfoUnderConstruction,然后再次进行check,如果新block的generation stamp小于等于最后一个block的generation stamp,或者字节数小于最后一个block的generation stamp,那么抛异常.否则更新最后一个block的字节数和generation stamp为新BlockInfo的值,并且设置好最后一个block的List replicas属性,每个replica的状态设置为RBW.

pipeline 建立好后,DataStreamer启动ResponseProcessor线程用于处理下游对packet的ack,接着DataStreamer从dataQueue中取出一个个的packet往pipeline发.最后拆除pipeline.

参考资料

hadoop-hdfs-2.4.1.jar

HDFS pipeline写 -- 客户端的更多相关文章

  1. HDFS pipeline写 -- datanode

    站在DataNode的视角,看看pipeline写的流程,本文不分析客户端部分,从客户端写数据之前拿到了3个可写的block位置说起. 每个datanode会创建一个线程DataXceiverServ ...

  2. 2 weekend110的HDFS的JAVA客户端编写 + filesystem设计思想总结

    HDFS的JAVA客户端编写  现在,我们来玩玩,在linux系统里,玩eclipse 或者, 即,更改图标,成功 这个,别慌.重新换个版本就好,有错误出错是好事. http://www.eclips ...

  3. HDFS的写数据过程分析

    HDFS的写数据过程分析 我们通过FileSystem类可以操控HDFS, 那我们就从这里开始分析写数据到HDFS的过程. 在我们向 HDFS 写文件的时候,调用的是 FileSystem.creat ...

  4. 一脸懵逼学习hadoop之HDFS的java客户端编写

    1:eclipse创建一个项目,然后导入对应的jar包: 鼠标右击项目,点击properties或者alt+enter快捷键--->java build path--->libraries ...

  5. 一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse)

    一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse) 给centOS安装图形界面 GNOME桌面环境 https://blog.csdn.net/wh211212/artic ...

  6. day03-hdfs的客户端操作\hdfs的java客户端编程

    5.hdfs的客户端操作 客户端的理解 hdfs的客户端有多种形式: 1.网页形式 2.命令行形式 3.客户端在哪里运行,没有约束,只要运行客户端的机器能够跟hdfs集群联网 文件的切块大小和存储的副 ...

  7. Linux启动kettle及linux和windows中kettle往hdfs中写数据(3)

    在xmanager中的xshell运行进入图形化界面 sh spoon.sh 新建一个job

  8. HDFS的Java客户端编写

    总结: 之前在教材上看hdfs的Java客户端编写,只有关键代码,呵呵…….闲话不说,上正文. 1. Hadoop 的Java客户端编写建议在linux系统上开发 2. 可以使用eclipse,ide ...

  9. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-9.使用JWT生成用户Token回写客户端

    笔记 9.使用JWT生成用户Token回写客户端     简介:讲解用户授权登录后,需要生成登录凭证重定向到页面上 1.获取当前页面访问地址 2.根据User基本信息生成token 3.重定向到指定页 ...

随机推荐

  1. 9.png图片制作详细教程

    1.背景自适应且不失真问题的存在      制作自适应背景图片是UI开发的一个广泛问题,也是界面设计师渴望解决的问题,我相信我们彼此都深有体会.      比如,列表的背景图一定,但是列表的高度随着列 ...

  2. CSS学习笔记(基础篇)

    CSS概念 CSS 指层叠样式表 (Cascading Style Sheets)(级联样式表) Css是用来美化html标签的,相当于页面化妆. 样式表书写位置: <head> < ...

  3. Linux笔记:linux常用命令

    文件目录操作 1.展示目录命令 ls # 展示当前目录下的可见文件 ls -a # 展示当前目录下所有的文件(包括隐藏的文件) ls -l # 展示当前目录下文件的详细信息 ll # 展示当前目录下文 ...

  4. Chrome插件下载地址

    www.crx4chrome.com可以直接下载 Chrome Store 插件 在chrome web store好像只能安装插件.

  5. java-forkjoin框架的使用

    ForkJoin是Java7提供的原生多线程并行处理框架,其基本思想是将大任务分割成小任务,最后将小任务聚合起来得到结果.fork是分解的意思, join是收集的意思. 它非常类似于HADOOP提供的 ...

  6. springboot-13-junitTest

    junitTest, 提喜欢用的一个方法, 在测试代码时非常好用 1, 添加maven依赖 <!-- 加入spring-test依赖 --> <dependency> < ...

  7. JAVA 之 多态 抽象 接口

    一:多态  1:多态   一个对象有多种形式的能力 2:步骤 1编写父类派生子类 2子类重写父类方法 3用父类的数据类型引用子类对象 3:静态多态的实现方式就是方法重载 4:动态多态的实现方式就是重写 ...

  8. MySQL中You can't specify target table for update in FROM clause异常

    mysql中You can't specify target table <tbl> for update in FROM clause错误的意思是说,不能先select出同一表中的某些值 ...

  9. hadoop学习笔记(五):HDFS Shell命令

    一.HDFS文件命令 以下是比较重要的一些命令: [root@master01 hadoop]# hadoop fs -ls / //查看根目录下的所有文件 [root@master01 hadoop ...

  10. [转]ng-grid Auto / Dynamic Height

    本文转自:https://stackoverflow.com/questions/23396398/ng-grid-auto-dynamic-height I think I solved this ...