站在DataNode的视角,看看pipeline写的流程,本文不分析客户端部分,从客户端写数据之前拿到了3个可写的block位置说起。

每个datanode会创建一个线程DataXceiverServer,接收上游过来的TCP连接,对于每个新建的TCP连接,都会创建一个叫做DataXceiver的线程处理这个连接. 这个线程不断的从TCP连接中读op,然后调用processOp(op)处理这个op,这里以write block 这个op为例.

对于datanode来说,write block操作由DataXceiver的writeBlock函数实现.

大体步骤如下:

  1. new 一个BlockReceiver对象,随后用于接收上游(client或者datanode)的block数据.

  2. 根据传进来的DatanodeInfo数组,向数组的第一个元素代表的datanode建立TCP连接,targets参数是从上游的TCP连接中解析出来的,逻辑在Receiver的opWriteBlock方法中,Receiver是DataXceiver的基类.然后调用Sender的writeBlock方法给下游datanode发送write block相关元信息,包括DatanodeInfo数组(刨去第一个元素),clientname,block的当前gs,minBytesRcvd,maxBytesRcvd(对于append,recovery操作有用)等。然后读取下游的回复封装在BlockOpResponseProto对象中,可以通过内部成员firstBadLink知道建pipeline中第一个失败的datanode节点。接着将BlockOpResponseProto回复给上游
    (datanode或者client),最后调用第一步new的BlockReceiver的receiveBlock方法用于接收一个完整的block.如下:

    receiveBlock内部根据clientname发现是一个客户端在写block,创建一个PacketResponder线程用于处理下游datanode对packet的ack.PacketResponder后面分析。接着,不断的调用receivePacket()方法从上游(datanode或者client)接收一个个的packet,接收一个完整的packet的逻辑是由内部的PacketReceiver来处理的.
    对于一个接收到的packet,写入block file文件,同时checksum信息写meta文件,然后放入PacketResponder的ack queue队列,然后将packet写给下游的datanode。最后调用PacketResponder的 close方法,这个方法会等到ack queue为空,即所有packet都已经从下游收到,并且已经给上游ack.

  3. receiveBlock()结束后,关掉和上下游的连接.

清空ack queue的逻辑由专门处理下游ack包的PacketResponder线程处理,逻辑如下:

  1. 如果datanode是pipeline的中间node(通过PacketResponder的type属性来决定,LAST_IN_PIPELINE和HAS_DOWNSTREAM_IN_PIPELINE),
    那么从下游读一个PipelineAck,从ack中拿到seqno,然后从ack queue中get(不删除)第一个packet,拿出seqno,记作expected_seq_no,然后比较是否相等,如果不相等,说明写出错. 如果seqno相同,往下.

  2. 如果从ack queue中get的packet是block的最后一个packet,说明一个block接收完成.那么调用finalizeBlock方法.finalizeBlock方法逻辑如下:

    关闭block file和meta file文件,调用FsDatasetImpl的finalizeBlock(block)将block文件以及对应的meta文件移动到对应的block pool下的finalized目录下,然后生成一个FinalizedReplica对象,将bpid->FinalizedReplica的映射关系记录在内存中的volumnMap中,对象位于FsDatasetImpl下的ReplicaMap volumnMap(从ReplicaMap中定位一个ReplicaInfo,需要拿着bpid和block id去找)最后调用datanode的closeBlock()方法,将block回报给namenode,该方法逻辑如下:

    拿着block的bpid从BlockPoolManager中拿到相应的BPOfferService,通知namenode这个block。在data node这边,data node和每个namenode的接口由一
    个BPServiceActor来承担,这是一个线程, 这个线程会向namenode汇报received block或者指示namenode去删除block.最后调用DatanodeProtocolClientSideTranslatorPB bpNamenode的blockReceivedAndDeleted()将block信息汇报上去.

  3. 给从下游接收的ack回复给上游。
  4. 将packet从ack queue的头部删除。

可以看出,一个block的写操作对于每个data node来说,由两个线程参与,一个是DataXceiver,用于接收上游的数据,一个是PacketResponder,用于处理下游回来的ack。还没有接收到下游的ack并且没有给上游回复ack的packet都存在在ack queue中。

参考资料

hadoop-hdfs-2.4.1.jar

HDFS pipeline写 -- datanode的更多相关文章

  1. HDFS pipeline写 -- 客户端

    上一篇说了datanode端如何处理pipeline写请求的,这里主要看DFSClient. 这里以append为例, write差不多. 创建一个pipeline用于append操作的流程: Fil ...

  2. HDFS dfsclient写文件过程 源码分析

    HDFS写入文件的重要概念 HDFS一个文件由多个block构成.HDFS在进行block读写的时候是以packet(默认每个packet为64K)为单位进行的.每一个packet由若干个chunk( ...

  3. HDFS的写数据过程分析

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

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

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

  5. hadoop之 解析HDFS的写文件流程

    文件是如何写入HDFS的 ? 下面我们来先看看下面的“写”流程图:  假如我们有一个文件test.txt,想要把它放到Hadoop上,执行如下命令: 引用         # hadoop fs  - ...

  6. hdfs webhdfs 写文件(create file)

    # _*_ coding=utf-8 _*_ import sys import os hosts = {} cmd1 = ''' curl -i -X PUT "http://%s:500 ...

  7. HDFS 读/写数据流程

    1. HDFS 写数据流程 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件, NameNode 检查目标文件是否已存在,父目录是否存在: NameNo ...

  8. HDFS数据节点DataNode未启动解决方法

    在解决这个问题的过程中,我又是积累了不少经验... 首先让我搞了很久的问题是,书上说进程全部启动的命令是/bin/start-all.sh,但是当我执行的时候显示command not found.后 ...

  9. HDFS 手写mapreduce单词计数框架

    一.数据处理类 package com.css.hdfs; import java.io.BufferedReader; import java.io.IOException; import java ...

随机推荐

  1. ASP.NET 负载均衡 StateServer Session共享问题(经验记录)

    (源地址:http://www.cnblogs.com/ryhan/p/3748976.html) 最近在改造公司的一个系统 支持F5硬件负载,由于系统后面还跟了个异步工具,需要将Admin上传的文件 ...

  2. 数字和表达式(python)

    >>>2+2 4 >>>1/2#(注:3.0版本之前是这样的,整数除法) >>>1.0/2.0 0.5 >>>1.0/2 0.5 ...

  3. WordPress导航菜单函数

    导航菜单是每一个WordPress主题必须的元素,如果你要制作一个WordPress主题,那就必须熟悉WordPress导航菜单注册函数 register_nav_menus() 和 导航菜单调用函数 ...

  4. OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)

    最新版本,之前的版本有些文件没有打包 视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440 OpenGL本身并没有绘 ...

  5. vue2.0实现购物车功能

    购物车功能是一件比较繁琐的事情,逻辑功能太多,今天就用vue2.0实现一个简单的购物车功能,数据都本地自己写的假数据 功能列表: 1.全选和单选结算 2.减少和增加数量 3.商品的删除 界面搭建以及布 ...

  6. webSQL的基本操作

    1.html5以来,数据的前端存储已经有了很大进步.这里简单些一下webSQL的基本用法.代码如下: <!DOCTYPE html> <html> <head> & ...

  7. springcloud-07-eureka HA的高可用配置

    单机版的eureka, 运行时间稍长, 就会在管理界面出现红色的警告, 为了消除这个警告, 可以使用eureka的高可用配置: 只需要写一个工程配置不同的配置文件, 然后启动多实例即可: 请参照单机版 ...

  8. java面试⑥框架部分

    2.5.1 什么是框架: 2.5.2 MVC模式 2.5.3 MVC框架 2.5.4 简单讲一下struts2的执行流程 2.5.5 Struts2中的拦截器,你都用它干什么? 2.5.6 简单讲一下 ...

  9. Java的Date类与Calendar

    一.Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Da ...

  10. es索引的RestHighLevelClient实现

    java代码: import java.io.IOException; import org.apache.http.HttpHost; import org.elasticsearch.action ...