HDFS源码解析(三)

17 篇文章 0 订阅
15 篇文章 0 订阅

本人博客针对的是hadoop2版本,比1版本略为复杂(采用了很多当下流行的设计模式,加入了新的序列化框架,ha配置,联邦特性,yarn框架,以及采用maven的工程划分结构等)。网上的源码分析大多针对的是1版本,由于是针对源码写出自己的理解,难免有错误或不当的地方,欢迎指正

前面两篇主要讲了namenode,现在来说说datanode。好了,直接打开idea,进入DataNode

首先我来翻译一下注释(有些是自己添加的):

/**********************************************************
 * DataNode is a class (and program) that stores a set of
 * blocks for a DFS deployment.  A single deployment can
 * have one or many DataNodes.  Each DataNode communicates
 * regularly with a single NameNode.  It also communicates
 * with client code and other DataNodes from time to time.
 *datanode是DFS调度存储一系列数据块的一个类或者说是程序。DFS调度可以有1个或多个数据节点。
 * 每个数据节点定期和唯一的namenode进行通信。有时它也和客户端或其他的数据节点通信。
 *
 * DataNodes store a series of named blocks.  The DataNode
 * allows client code to read these blocks, or to write new
 * block data.  The DataNode may also, in response to instructions
 * from its NameNode, delete blocks or copy blocks to/from other
 * DataNodes.
 *数据节点存储一系列命名数据块。它允许客户端读写或者创建新的数据块。而且,
 * 它还会执行来自namenode的删除数据块,拷贝或复制其他节点上的数据块的指令,
 * 当然了,这些指令是通过心跳的的响应时传达的
 *
 * The DataNode maintains just one critical table:
 *   block-> stream of bytes (of BLOCK_SIZE or less)
 *数据节点保存了极其重要的一张表:数据块到字节流的映射
 *
 * This info is stored on a local disk.  The DataNode
 * reports the table's contents to the NameNode upon startup
 * and every so often afterwards.
 *这个信息保存在本地磁盘上,数据节点在启动,以后定期把这些内容上报给namenode
 * 这就是前面文章中说的第三种元数据是由数据节点上报动态建立的
 *
 * DataNodes spend their lives in an endless loop of asking
 * the NameNode for something to do.  A NameNode cannot connect
 * to a DataNode directly; a NameNode simply returns values from
 * functions invoked by a DataNode.
 *datanode是一个死循环并一直询问namenode有什么事吩咐。namenode不可以直接连接datanode,
 *它只能通过datanode的请求函数中返回值
 *
 * DataNodes maintain an open server socket so that client code 
 * or other DataNodes can read/write data.  The host/port for
 * this server is reported to the NameNode, which then sends that
 * information to clients or other DataNodes that might be interested.
 *数据节点保持一个打开的套接字供客户端和其他数据节点读写数据。当前的主机名,
 * 端口要上报给namenode,然后namenode再发给其他感兴趣的客户端或数据节点
 *
 **********************************************************/

接着,同namenode分析思路,直接进入main方法

public static void main(String args[]) {
    if (DFSUtil.parseHelpArgument(args, DataNode.USAGE, System.out, true)) { // 在namenode中见过吧,解析命令行参数,其实在hadoop1中是没有这个if判断的
      System.exit(0);
    }

    secureMain(args, null);
  }
public static void secureMain(String args[], SecureResources resources) {
    int errorCode = 0;
    try {
      StringUtils.startupShutdownMessage(DataNode.class, args, LOG); // 打印启动关闭信息
      DataNode datanode = createDataNode(args, null, resources); 
// 看到没,跟namenode一个编码思路,
// 创建datanode时会调用instantiateDataNode方法,进行初始化配置信息,权限设置。
// 在hadoop1里面有行代码是
// String[] dataDirs = conf.getStrings(DATA_DIR_KEY);而在hadoop2里面是
// Collection<StorageLocation> dataLocations = getStorageLocations(conf);
// hadoop2对其做了下封装,显得更规范。java你懂得,
// 不抽出点接口、进行点包装显示不出自己的逼格。其实就是获取数据存储目录。
	if (datanode != null) {
        datanode.join();
 // 还记得namenode中是启动两大rpcserver吗,下面详细解析join方法
      } else {
        errorCode = 1;
      }
    } catch (Throwable e) {
      LOG.fatal("Exception in secureMain", e);
      terminate(1, e);
    } finally {
      // We need to terminate the process here because either shutdown was called
      // or some disk related conditions like volumes tolerated or volumes required
      // condition was not met. Also, In secure mode, control will go to Jsvc
      // and Datanode process hangs if it does not exit.
      LOG.warn("Exiting Datanode");
      terminate(errorCode);
    }
  }

在createDataNode中,你还会看到runDatanodeDaemon方法

  public void runDatanodeDaemon() throws IOException {
    blockPoolManager.startAll();

    // start dataXceiveServer
    // DataXceiverServer类是DataNode的辅助类,
    // 它最主要是用来实现客户端或其他数据节点与当前节点通信,
    // 并负责接收/发送数据块。这个类的创建是为了监听来自客户端或其他数据节点的请求。
    // 它的实现通信的方法不是用hadoop IPC,而是用jdk本身就有的ServerSocket。
    // DataXceiverServer是一个简单的tcp socket server, 监听特定的端口,
    // 持有一个单独的线程,不断调用accept,如果有请求过来,
    // 就创建一个DataXceiver线程并启动,进行处理
    dataXceiverServer.start();
    if (localDataXceiverServer != null) {
      localDataXceiverServer.start();
    }
    ipcServer.start();
    startPlugins(conf);
  }

在datanode.join中有吊用下面的join方法

 void join() {
    while (shouldRun) {
      try {
        // BlockPoolManager类提供管理BlockPool的相关API,在hadoop2中允许存在多个namespace
        // 其中,BPOfferService为每个Namespace下每个BlockPool一个实例,
        // 提供BlockPool对它所对应的Namespace的操作的相关API,
        // BPOfferService为指定Namespace中每个namenode一个实例,
        // 自已持有线程,定时向它所对应的namenode发heartbeat, blockreport,
        // 并执行namenode通过heartbeat/blockreport response传回来的command
        blockPoolManager.joinAll();
        if (blockPoolManager.getAllNamenodeThreads() != null
            && blockPoolManager.getAllNamenodeThreads().length == 0) {
          shouldRun = false;
        }
        // Terminate if shutdown is complete or 2 seconds after all BPs
        // are shutdown.
        synchronized(this) {
          wait(2000);
        }
      } catch (InterruptedException ex) {
        LOG.warn("Received exception in Datanode#join: " + ex);
      }
    }
  }

在datanode类中还有DataBlockScanner线程,类型为volatile 。

(Java语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”,目前还挺有争议的。)

DataBlockScanner的主要功能是扫描并校验磁盘上的data block, 把发现的坏块报告给namenode. 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值