NameNode启动流程分析
一、shell调用梳理
启动hdfs的shell脚本是
${HADOOP_HDFS_HOME}/sbin/start-dfs.sh
其中在启动namenode、datanode、secondarynamenode、journalnode、zkfc等服务时都是调用了
${HADOOP_PREFIX}/sbin/hadoop-daemons.sh
其中会首先调用hadoop-config.sh,在这里加载了各种配置
然后调用
最终调用了/bin/hdfs
在hdfs脚本中,直接使用java命令调用了
org.apache.hadoop.hdfs.server.namenode.NameNode
org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode
org.apache.hadoop.hdfs.server.datanode.DataNode
等类
二、NameNode类分析
首先大致浏览了一下这个类,其中看到感兴趣的类就点进去大致看一眼,总体上看这个类的内容写的很明白
然后开始从入口看代码
public static void
main
(String argv[])
throws
Exception {
//
判断参数是否是打印帮助信息
if
(DFSUtil.
parseHelpArgument
(argv
,
NameNode.
USAGE
,
System.
out
, true
)) {
System.
exit
(
0
)
;
}
try
{
//
打印
startup
信息,并且增加
shutdown
的钩子函数(该函数打印
shutdown
信息)
StringUtils.
startupShutdownMessage
(NameNode.
class,
argv
,
LOG
)
;
//
所有
namenode
相关启动命令调用统一的方法
NameNode namenode =
createNameNode
(argv
, null
)
;
//
如果
namenode
不为
null
,则表明是调用的启动
namenode
方法。这时候应该调用
namenode
的
join
方法等待服务关闭
if
(namenode !=
null
) {
namenode.join()
;
}
}
catch
(Throwable e) {
LOG
.fatal(
"Failed to start namenode."
,
e)
;
terminate
(
1
,
e)
;
}
}
namenode初始化代码
protected
NameNode
(Configuration conf
,
NamenodeRole role)
throws
IOException {
this
.
conf
= conf
;
this
.
role
= role
;
setClientNamenodeAddress(conf)
;
String nsId = getNameServiceId(conf)
;
String namenodeId = HAUtil.
getNameNodeId
(conf
,
nsId)
;
this
.
haEnabled
= HAUtil.
isHAEnabled
(conf
,
nsId)
;
state
= createHAState(
getStartupOption
(conf))
;
this
.
allowStaleStandbyReads
= HAUtil.
shouldAllowStandbyReads
(conf)
;
this
.
haContext
= createHAContext()
;
try
{
initializeGenericKeys
(conf
,
nsId
,
namenodeId)
;
//
这里真正初始化
namenode
服务
initialize(conf)
;
try
{
haContext
.writeLock()
;
state
.prepareToEnterState(
haContext
)
;
state
.enterState(
haContext
)
;
}
finally
{
haContext
.writeUnlock()
;
}
}
catch
(IOException e) {
this
.stop()
;
throw
e
;
}
catch
(HadoopIllegalArgumentException e) {
this
.stop()
;
throw
e
;
}
this
.
started
.set(
true
)
;
}
真正的初始化操作
protected void
initialize
(Configuration conf)
throws
IOException {
if
(conf.get(
HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS
) ==
null
) {
String intervals = conf.get(
DFS_METRICS_PERCENTILES_INTERVALS_KEY
)
;
if
(intervals !=
null
) {
conf.set(
HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS
,
intervals)
;
}
}
//
设置
ugi
UserGroupInformation.
setConfiguration
(conf)
;
loginAsNameNodeUser(conf)
;
//
统计
namenode
各种信息
NameNode.
initMetrics
(conf
, this
.getRole())
;
StartupProgressMetrics.
register
(
startupProgress
)
;
//
如果是正常服务的
namenode
,需要为他启动一个
httpserver
(
namenode
的
web
界面,一路点进去可以看到默认端口是
50070
)
if
(NamenodeRole.
NAMENODE
==
role
) {
startHttpServer(conf)
;
}
this
.
spanReceiverHost
= SpanReceiverHost.
getInstance
(conf)
;
//
从硬盘中实例化
namesystem,namesystem
中初始化了
BlockManager
、
CacheManager
等
loadNamesystem(conf)
;
//
创建
rpc
服务,主要是创建了
serviceRpcServer
和
clientRpcServer
分别监听
datanode
和客户端的请求
rpcServer
= createRpcServer(conf)
;
if
(
clientNamenodeAddress
==
null
) {
// This is expected for MiniDFSCluster. Set it now using
// the RPC server's bind address.
clientNamenodeAddress
=
NetUtils.
getHostPortString
(
rpcServer
.getRpcAddress())
;
LOG
.info(
"Clients are to use "
+
clientNamenodeAddress
+
" to access"
+
" this namenode/service."
)
;
}
if
(NamenodeRole.
NAMENODE
==
role
) {
httpServer
.setNameNodeAddress(getNameNodeAddress())
;
httpServer
.setFSImage(getFSImage())
;
}
pauseMonitor
=
new
JvmPauseMonitor(conf)
;
pauseMonitor
.start()
;
metrics
.getJvmMetrics().setPauseMonitor(
pauseMonitor
)
;
//
启动
rpc
等服务(以及
standby
的
namenode
的相关服务)
startCommonServices(conf)
;
}
启动其他的一些通用服务
private void
startCommonServices
(Configuration conf)
throws
IOException {
//
启动
namesystem
的相关服务,包括检查硬盘容量等
//
另外,进入
SafeMode
状态,等待
datanode
报告
block
情况
namesystem
.startCommonServices(conf
,
haContext
)
;
registerNNSMXBean()
;
//
为
standby
的
namenode
启动
http
服务
if
(NamenodeRole.
NAMENODE
!=
role
) {
startHttpServer(conf)
;
httpServer
.setNameNodeAddress(getNameNodeAddress())
;
httpServer
.setFSImage(getFSImage())
;
}
//
启动
rpc
服务
rpcServer
.start()
;
//
加载
rpc
服务插件(自定义
rpc
调用方法)
plugins
= conf.getInstances(
DFS_NAMENODE_PLUGINS_KEY
,
ServicePlugin.
class
)
;
for
(ServicePlugin p:
plugins
) {
try
{
p.start(
this
)
;
}
catch
(Throwable t) {
LOG
.warn(
"ServicePlugin "
+ p +
" could not be started"
,
t)
;
}
}
LOG
.info(getRole() +
" RPC up at: "
+
rpcServer
.getRpcAddress())
;
if
(
rpcServer
.getServiceRpcAddress() !=
null
) {
LOG
.info(getRole() +
" service RPC up at: "
+
rpcServer
.getServiceRpcAddress())
;
}
}