1 . nameNode的main方法调用createNameNode
2 . 进行一串switch case 后,并没有匹配到对应初始化的类型,走default
default: {
DefaultMetricsSystem.initialize("NameNode");
//TODO
return new NameNode(conf);
}
3 . new NameNode执行:调用initialize(conf);初始化方法
init方法内进行的四步操作
(1)启动httpserver服务,开放50070端口 :
startHttpServer(conf);
getHttpServerBindAddress(conf)); 设置主机名和端口号
设置50070端口
InetSocketAddress bindAddress = getHttpServerAddress(conf);
DFS_NAMENODE_HTTP_PORT_DEFAULT = 50070;
httpServer.start(); 启动HttpServer服务,开放50070端口
创建httpserver2对象
HttpServer2.Builder builder = DFSUtil.httpServerTemplateForNNAndJN(conf,
httpAddr, httpsAddr, "hdfs",
DFSConfigKeys.DFS_NAMENODE_KERBEROS_INTERNAL_SPNEGO_PRINCIPAL_KEY,
DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY);
httpServer = builder.build();
绑定servlet
setupServlets(httpServer, conf);
这个servlet使得50070得以使用
httpServer.addInternalServlet("listPaths", "/listPaths/*",
ListPathsServlet.class, false);
启动
httpServer.start();
(2)加载元数据【 集群刚刚启动时,正常情况下并没有什么元数据需要加载【如果有数据需要加载,那么上一次程序结束因该是因为故障而宕机了
loadNamesystem(conf);
this.namesystem = FSNamesystem.loadFromDisk(conf);
加载元数据【即fsimage
namesystem.loadFSImage(startOpt);
合并元数据 :fsimage + editLog 生成新的 fsimage(在内存中)
fsImage.recoverTransitionRead
将合并完的元数据保存到磁盘上
fsImage.saveNamespace(this);
打开一个新的editLog用来写日志
fsImage.openEditLogForWrite();
(3)创建NameNodeRPC服务端
rpcServer = createRpcServer(conf);
返回一个NameNodeRpcServer对象
return new NameNodeRpcServer(conf, this);
new的过程中创建服务端(注,服务启动的代码其实在NameNodeRPCServer内,而NameNode类内其实包括了这个类的对象)
this.serviceRpcServer = new RPC.Builder(conf)
.setProtocol(
org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB.class)
.setInstance(clientNNPbService)
.setBindAddress(bindHost)
.setPort(serviceRpcAddr.getPort()).setNumHandlers(serviceHandlerCount)
.setVerbose(false)
.setSecretManager(namesystem.getDelegationTokenSecretManager())
.build();
(4)启动其他服务
startCommonServices(conf); 启动 元数据管理 和 上文创建的NameNodeRPC服务端
元数据管理
namesystem.startCommonServices(conf, haContext);
检查是否有足够的磁盘储存元数据,根据检查结果将hasResourcesAvailable的值修改为true或false
checkAvailableResources();
安全模式
setBlockTotal();
设置安全模式
safeMode.setBlockTotal((int)getCompleteBlocksTotal());【getCompleteBlocksTotal()返回能正常使用的block的数量
计算阈值
this.blockThreshold = (int) (blockTotal * threshold);
检查安全模式
checkMode();
判断 是否已经处于安全模式/是否需要进入安全模式 【needEnter()
if (smmthread == null && needEnter())
needEnter()方法内部进行安全模式判别
{
return (threshold != 0 && blockSafe < blockThreshold) || (1)
(datanodeThreshold != 0 && getNumLiveDataNodes() < datanodeThreshold) || (2)
(!nameNodeHasResourcesAvailable()); (3)
(1):存活的block小于block正常工作的阈值时
(2):存活节点数小于某一个自定义值时,进入安全模式(此条件默认不生效,datanodeThreshold默认为0)
(3):上文磁盘空间判定为不足时【即方法checkAvailableResources();
}
判断为已经处于安全模式或需要进入安全模式,进行一些安全模式需要的参数的初始化
enter();
启动服务
blockManager.activate(conf);
启动 等待复制的block 线程?
pendingReplications.start();
启动心跳管理服务
datanodeManager.activate(conf);
管理下线的datanode
decomManager.activate(conf);
管理心跳
heartbeatManager.activate(conf);
启动了heartbeatThread线程
heartbeatThread.start();
RPC服务端启动【NameNodeRPCServer
rpcServer.start();