Hadoop-0.20.2源码学习(5)——初识DataNode启动过程

参考: JeffreyZhou的博客园
《Hadoop权威指南》第四版

上一篇文章中讲到,DataNode.java中的main函数:

public static void main(String args[]) {
    try {
      StringUtils.startupShutdownMessage(DataNode.class, args, LOG);
      DataNode datanode = createDataNode(args, null); //
      if (datanode != null)
        datanode.join();
    } catch (Throwable e) {
      LOG.error(StringUtils.stringifyException(e));
      System.exit(-1);
    }
  }

我们在上一篇的后半部分,顺着startupShutdownMessage()的线索,去摸索了一下在启动和关闭时的 MSG 来源,接下来的createDataNode()才是DN的初始化呢。

5.1 先看下源码中的注释

从main函数中开始运行,创建DataNode对象,然后在runDatanodeDaemon函数创建了一个线程,然后程序调用了线程就停留在哪里了。

在DataNode源代码的注释中:

DataNodes spend their lives in an endless loop of asking the NameNode for sth. to do. A NameNode cannot connect to a DataNode directly; a NameNode simply returns values from functions invoked by a DataNode.

DataNodes maintain an open server sockets so that client code or other DataNodes can read/write data. the host/port for this server is reported to NameNode. which then sends that information to clients or other DataNodes that might be interesed.

从我个人理解来看,就是说哦,DN开启线程运行后,就一直处于轮询状态,socket一直打开状态,并把host/port报告给NN,记录下来,等有客户端或者其他DN需要的时候,找到NN,查到该host/port,就可以直接从DN读写数据,而不用经过NN这个中间商赚差价。

这也就是为什么第一段说,NN不能直接连接DN,而是返回一些值,而DN一直处于循环中,他等的不是主人(NN),而是客户(client)。

借助《Hadoop权威指南》中的图看一下:

在这里插入图片描述

所以,DataNode总的来说,初始化就是两块,创建对象,运行线程,然后waiting for request。

5.2 主要函数

public static DataNode createDataNode(String args[], Configuration conf) {
	DataNode dn = instantiateDataNode(args, conf);
	runDatanodeDaemon(dn);
	return dn;
}

在源码中顺着createDataNode(args, null)一步步往下探索,大概的整理了一下所用到的主要函数,在此用xmind大概的画了一下:

在这里插入图片描述

其中有4个备注地方;

  1. instantiateDataNode(args, conf)
    检查参数,配置文件是否存在/有效;检查参数,配置文件是否存在/有效;
    获取tmp/data/dfs/data里的内容;
  2. makeInstance (dataDirs,conf)
    检查dirs是否存在/有效;
    存储有效的dirs列表,即有效的DN节点;
  3. new DataNdoe (conf, dirs)
    新建Datanode对象
  4. startDataNode (conf, dataDirs)
    初始化完毕,开启socket等,开启datanode

DataNode启动前的动作大致就是上述这些流程了。也比较好理解、

接下来将其中各个函数列出来看一下。

5.3 instantiateDataNode函数

public static DataNode instantiateDataNode(String args[], Configuration conf) {
// 判断参数是否为空
	if(conf == null)
		conf = new Configuration();
	if(!parseArguments(args, conf)) {
		printUsage();
		return null;
	}
// 判断该配置是否有效
//	if(conf.get("dfs.network,scirpt") != null) {
//		LOG.error("This configuration for rack identification is not supported anymore");
//		System.exit(-1);
//	}
// 获取tmp/dfs/data
	String[] dataDirs = conf.getString("dfs.data.dir");
	dnThreadName = "DataNode:["+StringUtils.arratToString(dataDirs)+"]";
	return makeInstance(dataDirs, conf);
}

这里面的"dfs.data.dir",大家有没有感觉有点熟悉啊?而且用的还是Configuration.getString(),回忆一下。

结合前面几篇文章里的,Configuration类读取的就是core-site.xml等文件里面的内容,这些.xml文件就是在最开始,配置(伪)分布式环境时,所编辑的配置文件。依稀记得,有一个xml文件里面是有这个属性的,咱去找找。

果然,在hdfs-site.xml里面看到这两个配置:

		<property>
                <name>dfs.namenode.name.dir</name>
                <value>file:/usr/local/hadoop/tmp/dfs/name</value>
        </property>
        
		<property>
                <name>dfs.datanode.data.dir</name>
                <value>file:/usr/local/hadoop/tmp/dfs/data</value>
        </property>

既然知道了这个目录,那咱就去找一找这个目录下是啥玩意儿:

奇怪的是,我刚开始并没有找到这个目录,只看到了dfs.namenode.name.dir的位置,突然想起,我现在操作的是Masrer节点,而Data应该是在Slave节点中,去看看。
在这里插入图片描述

果然有东西, 但是怎么只有一个文件夹呢,看源码中,返回的类型是String[]类型啊,一个文件夹也成为一个数组啦?不对,虽然每个DN中只有一个文件夹,但是咱有好几个DN呢,嗯,果真是数组。

等等,这个文件夹好像也有点印象,打开看看:

在这里插入图片描述

乖乖,这不就是在最开始搭建分布式环境时,因为错误执行了hadoop namenode -format后,导致运行失败的原因所在地么。

有兴趣的可以看看我遇过的坑 Hadoop实践学习中的问题汇总(持续补充)

好了,这到底干啥用的后面再看吧,总之知道了,这个dataDirs中作用应该就是查到与NN对应的DN的id啊之类的信息匹配上吧。

5.4 makeInstance函数


public static DataNode makeInstance(String[] args, Configuration conf) {
	ArrayList<File> dirs = new ArrayList<File>();
	for(int i = 0; i < dataDirs.length; i++) {
		File data = new File(dataDirs[i]);
		DiskChecker.checkDir(data);
		dirs.add(data);
	}
	if(dirs.size() > 0)
		return new DataNoede(conf, dirs);
	LOG.error("All directories in dfs.dir are invalid.");
	return null
}

上面讲了获取的dataDirs是啥内容了,这里就是对获取到的内容,挨个检查,可能是防止一些有问题的DN混进来吧。比如(个人猜测)某个DN起初是在正常的,但是出故障了,被NN解除掉了。

好了,筛掉了滥竽充数的,接下来就为每个DN构造对象了。

5.5 DataNode构造函数

DataNode(Configuration conf, AbstractList<File> dataDirs) {
	super(conf);
	datanodeObject = this;
	startDataNode(conf, dataDirs);
}

构造函数很简单,就是创建一个对象,调用启动函数。

关于startDataNode(conf, dataDirs);,这里就暂时不深究了,大概看了一下,就是启动Socket之类的,按照本文开头说的,启动之后,就是不停的向NN轮询之类的,具体内容我还需要再练练级才能来闯。。。

5.6 别忘了还有runDatanodeDaemon函数呢

前面一系列都是操作都是实例化DN对象,然后在runDatanodeDaemon函数创建了一个线程,然后程序调用了线程就停留在哪里了。

换句话说,整个DataNode目前看来,就是一个大线程在跑。

这里有两个地方讲一下:

  1. SetDaemon(true):这个函数的意义,并非是简单的字面意义了(Daemon:守护),一般情况下,当一个线程还没运行完,主程序是卡住的,但设置为daemon为true时,当主程序结束,则线程也就自动结束。
  2. Join():这个函数就是等待线程结束后再往下走。就相当于我们常在主序中写的while(true){}一样。

java多线程 —— 创建线程的两种方法:

  1. 继承Thread类,复写run()方法,new此类对象,调用start()方法;
  2. 实现Runnable接口,复写run()方法,new此类对象,作为Thread类的参数启动。

继承Thread类方法不太方便,因为一个类只能继承一个类,但可继承多个接口,所以用接口更加灵活。

5.x 后记

这里大概的知道了一下DN的启动过程,至于在运行过程中的各种操作后面用到再来研究。

根据DN和NN中的main函数表现,我估计NN的启动过程应该也差不多,毕竟也要检查configuration和dfs.namenode.name.dir之类的配置和参数,但应该要比DN多一些内容,毕竟人家是领导层,权利越大,责任越大。

顺便查看了一下dfs.namenode.name.dir,即/usr/local/hadoop/tmp/dfs/name</value>里的内容,其实和DN一样的形式。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值