在conf/start-dfs.sh里可以看到,"$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start datanode $dataStartOpt,这个是用来启动一个datanode的。
因此和namenode一样,先到DataNode的main方法里:
有这样一句:DataNode datanode = createDataNode(args, null);,这行代码就是对用来初始化一个datanode的。
public static DataNode createDataNode(String args[],
Configuration conf) throws IOException {
DataNode dn = instantiateDataNode(args, conf);
runDatanodeDaemon(dn);
return dn;
}
可以很清楚地看到共有两部分操作,一个是初始化datanode,一个是开启datanode的后台线程。
一.初始化datanode
略去细节部分,
instantiateDataNode()--->makeInstance()--->new DataNode()--->startDataNode()
主要的初始化工作是在startDataNode方法中进行的。通过分析可以知道:主要的初始化工作分为一下几个步骤:
1.从配置文件中读取一些相关的配置参数,比如nameNodeAddr,socketTimeout,socketWriteTimeout等;
2.通过RPC获取namenode的proxy,并获取namenode的相关信息NamespaceInfo;
this.namenode = (DatanodeProtocol) RPC.waitForProxy(DatanodeProtocol.class,
DatanodeProtocol.versionID,
nameNodeAddr,
conf);
NamespaceInfo nsInfo = handshake();
3.检查文件系统状态并进行恢复,同时初始化datanode的内部数据结构FSDataset
storage.recoverTransitionRead(nsInfo, dataDirs, startOpt);
// adjust
this.dnRegistration.setStorageInfo(storage);
// initialize data node internal structure
this.data = new FSDataset(storage, conf);
4.寻找一个空闲端口并初始化DataXceiverServer
5.创建DataBlockScanner,创建HttpServer,启动ipc server
二.开启datanode的后台线程
后台线程是通过runDatanodeDaemon方法:
public static void runDatanodeDaemon(DataNode dn) throws IOException {
if (dn != null) {
//register datanode
dn.register();
dn.dataNodeThread = new Thread(dn, dnThreadName);
dn.dataNodeThread.setDaemon(true); // needed for JUnit testing
dn.dataNodeThread.start();
}
}
在开启后台线程之前,先对datanode进行注册,注册信息dnRegistration在第一步初始化的时候已经将相关信息记录到dnRegistration。向namenode注册的作用:是datanode向namenode报告它的一些存储信息,同时namenode会检查datanode的信息并且进行一些更新工作等。
注册成功之后,会启动datanode的后台线程,也就是调用DataNode的run方法(DataNode本身就实现了runnable接口)。
public void run() {
LOG.info(dnRegistration + "In DataNode.run, data = " + data);
// start dataXceiveServer
dataXceiverServer.start();
while (shouldRun) {
try {
startDistributedUpgradeIfNeeded();
offerService();
} catch (Exception ex) {
LOG.error("Exception: " + StringUtils.stringifyException(ex));
if (shouldRun) {
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
}
}
}
LOG.info(dnRegistration + ":Finishing DataNode in: "+data);
shutdown();
}
可以看到datanode无论发生异常与否都会一直循环运行(除非shutdown), startDistributedUpgradeIfNeeded();是升级用的,offerService是正常工作:
在offerService中主要做三方面的工作:定时向NameNode发送心跳(namenode.sendHeartbeat);报告最新收到的block数据(namenode.blockReceived);报告本地存储的block信息namenode.blockReport。
最后附上DataNode的类图: