上一篇说了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. CSS_Spirte实现原理 分类: HTML+CSS 2015-04-28 22:58 531人阅读 评论(0) 收藏

    CSS Spirte就是所谓的把很多的小图标合并成一张大的图片,然后使用CSS的background-position属性,来动态的定位自己需要图标的位置.这样做的目的主要是减少HTTP请求,加快网页 ...

  2. Exceptionless搭配log4net记录日志

    接上篇: Exceptionless 本地部署 在部署完成后可以使用log4net搭配Exceptionless来记录日志. 过程很简单,使用Nuget安装Exceptionless.Log4net, ...

  3. notepad++中设置python运行

    1. Notepad++ ->"运行"菜单->"运行"按钮 2. 在弹出的窗口内输入以下命令: cmd /k python "$(FULL ...

  4. springboot-17-springboot的文件上传和下载

    单文件上传 1, 需要使用thymeleaf模板:  http://www.cnblogs.com/wenbronk/p/6565834.html src/main/resource/template ...

  5. Linux用户信息查询

    1 查询目前已登录的用户信息w 或者 who [@bjzw_11_210 ~]# w :: up days, :, users, load average: 0.03, 0.04, 0.00 USER ...

  6. 为 Nginx 创建 windows 服务自启动

    1.下载最新版的 Windows Service Wrapper 程序 下载地址:http://download.java.net/maven/2/com/sun/winsw/winsw/1.9/ 2 ...

  7. lazy-mock ,一个生成后端模拟数据的懒人工具

    lazy-mock   lazy-mock 是基于koa2构建的,使用lowdb持久化数据到JSON文件.只需要简单的配置就可以实现和json-server差不多的功能,但是比json-server更 ...

  8. Deep Q-Network 学习笔记(六)—— 改进④:dueling dqn

    这篇同样是完全没看懂 Orz,这里只做实现记录.. 要改动的地方只是在神经网络的最后一层做下调整即可. def create(self): neuro_layer_1 = 3 w_init = tf. ...

  9. js 背景自动切换

    //首页自动更换背景特效开始============================================ var curIndex = 0; //时间间隔(单位毫秒),每秒钟显示一张,数组 ...

  10. (一)面向对象的javascript

    javascript是一门典型的动态类语言 一:鸭式辨型(指导我们关注对象的行为,而不关注对象本身). var duck = { duckString: function(){ console.log ...