Hadoop源码学习笔记之NameNode启动场景流程二:http server启动源码剖析
NameNodeHttpServer启动源码剖析,这一部分主要按以下步骤进行:
一、源码调用分析
二、伪代码调用流程梳理
三、http server服务流程图解
第一步,源码调用分析
前一篇文章已经锁定到了NameNode.java类文件,搜索找到main(),可以看到代码只有寥寥几行,再筛除掉一些参数校验以及try-catch逻辑代码,
剩下的核心的代码甚至只有两行,如下:
public static void main(String argv[]) throws Exception {
if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
System.exit(0);
} try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
NameNode namenode = createNameNode(argv, null);
if (namenode != null) {
namenode.join();
}
} catch (Throwable e) {
LOG.fatal("Failed to start namenode.", e);
terminate(1, e);
}
}
根据main()里面的代码,可以得知主流程是:1.创建NameNode对象,2.调用join()方法。然后深入到createNameNode()方法中,如下:
public static NameNode createNameNode(String argv[], Configuration conf)
throws IOException {
LOG.info("createNameNode " + Arrays.asList(argv));
if (conf == null)
conf = new HdfsConfiguration();
......// Parse the rest, NN specific args.
StartupOption startOpt = parseArguments(argv);
if (startOpt == null) {
printUsage(System.err);
return null;
}
// 重要代码:设置解析出来的参数。
setStartupOption(conf, startOpt); switch (startOpt) {
// 如果传递的是-format,就是告诉namenode要做目录结构的格式化,其他的也同理。
case FORMAT: {
boolean aborted = format(conf, startOpt.getForceFormat(),
startOpt.getInteractiveFormat());
terminate(aborted ? 1 : 0);
return null; // avoid javac warning
}
......
case ROLLBACK: {
boolean aborted = doRollback(conf, true);
terminate(aborted ? 1 : 0);
return null; // avoid warning
}
......
default: {
// 核心代码:如果正常情况下启动一个NameNode进程,代码会执行到此处,实例化一个NameNode对象。
DefaultMetricsSystem.initialize("NameNode");
return new NameNode(conf);
}
}
}
这段代码看着很长,其实最重要的也就标粗的两行:
- setStartupOption(conf, startOpt);
这行代码是用来设置解析出来的参数。比如执行一条shell命令:hdfs namenode -format,其中的-format就是作为参数传递进来
进行解析,然后经过下面的switch()进行判断,进入到格式化的代码部分。其他的Hadoop命令参数比如-rollback也同理,都会进入
到这个switch(),根据传入的参数去执行相应的功能代码。
- new NameNode(conf);
switch()里前面的选择都是一些NameNode的功能模块,比如初始化、回滚、产生集群id等,而正常情况下启动NameNode进程会进入
到default模块,在这里会实例化一个NameNode对象。
接下来,就继续dive into到NameNode的构造方法中:
protected NameNode(Configuration conf, NamenodeRole role)
throws IOException {
// 初始化一些参数及配置
this.conf = conf;
this.role = role;
setClientNamenodeAddress(conf);
......
try {
initializeGenericKeys(conf, nsId, namenodeId);
// 核心代码:初始化NameNode实例对象。
initialize(conf);
try {
......
} catch (HadoopIllegalArgumentException e) {
this.stop();
throw e;
}
this.started.set(true);
}
可以看到除了上面的一些参数配置之外,最重要的一行代码就是initialize()方法了。也可以根据NameNode的注释说明结合集群启动命令等
推测到,NameNodeServer的代码肯定是在这个初始化方法里面。继续往下深入,
protected void initialize(Configuration conf) throws IOException {
// 可以通过找到下面变量名的映射,在hdfs-default.xml中找到对应的配置
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);
}
} ...... // 核心代码:启动HttpServer
if (NamenodeRole.NAMENODE == role) {
startHttpServer(conf);
} this.spanReceiverHost = SpanReceiverHost.getInstance(conf); // 核心代码:后面FSNamesystem初始化篇研究
loadNamesystem(conf); // 核心代码:后面rpc server启动流程篇研究
rpcServer = createRpcServer(conf); ...... startCommonServices(conf);
}
这一段代码里面,核心代码有三行,但是目前只针对http server启动流程进行挖掘,下面两行核心代码会有专门的篇章去针对性的研究。
继续深入startHttpServer()方法,
private void startHttpServer(final Configuration conf) throws IOException {
httpServer = new NameNodeHttpServer(conf, this, getHttpServerBindAddress(conf));
// 核心代码
httpServer.start();
httpServer.setStartupProgress(startupProgress);
}
继续深入httpServer.start()方法,看看里面都做了哪些事情,
void start() throws IOException {
HttpConfig.Policy policy = DFSUtil.getHttpPolicy(conf);
final String infoHost = bindAddress.getHostName(); // 重要代码
final InetSocketAddress httpAddr = bindAddress;
final String httpsAddrString = conf.get(
DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY,
DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_DEFAULT);
InetSocketAddress httpsAddr = NetUtils.createSocketAddr(httpsAddrString); ...... // 重要代码
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(); ...... initWebHdfs(conf); httpServer.setAttribute(NAMENODE_ATTRIBUTE_KEY, nn);
httpServer.setAttribute(JspHelper.CURRENT_CONF, conf); // 核心代码:HttpServer2绑定了一堆servlet,定义好了接收哪些http请求,接收到了请求由谁来处理。
setupServlets(httpServer, conf);
// 核心代码:启动httpServer
httpServer.start(); ......
}
这段代码中的bindAddress,经过一步一步的溯源,可以对应到hdfs-default.xml中的这段属性:
<property>
<name>dfs.namenode.http-address</name>
<value>0.0.0.0:50070</value>
<description>
The address and the base port where the dfs namenode web ui will listen on.
</description>
</property>
可以得知bindAddress就是http server绑定在哪个端口上,默认是0.0.0.0:50070,当然也可以自己配置。结合以往的集群启动经验,启动成功后
我们一般会在浏览器访问http://xx.xx.xx.xx:50070这个hdfs管理工作台,可以查看集群的状态、元数据、目录结构、block信息等。这其实就是
NameNode的http server提供的服务。
具体http server是什么?往下看会有这么一行代码:
HttpServer2.Builder builder = ....;
httpServer = builder.build();
这段代码指示了http server是具体的哪个类——HttpServer2.java。这个类是Hadoop实现的一套http服务,用于接收http请求。并且这一块是
Hadoop抽离出来独立的一个模块,在hadoop-common包中,是整个Hadoop框架通用的一套http server服务。具体怎么实现的不在本篇研究
范围,就不做深究了。
继续往下看,setupServlets(); 这一行是核心代码,点进去发现是绑定了各种参数的servlet。这些servlet定义了接收哪些http请求,并且接收到
请求之后由哪个servlet进行处理。举个栗子,我们在浏览器请求了http://xx.xx.xx.xx:50070/listPath?path=/user/warehouse,此时HttpServer2
接收到请求,然后转发给对应的处理listPath功能的servlet,servlet处理完之后再将结果返回。
最后,就是httpServer.start()了,代码执行到此处会启动httpServer,然后客户端都可以通过http请求进行访问了。
第二步,伪代码调用流程梳理。
NameNode.main() // 入口函数
|——createNameNode(); // 通过new NameNode()进行实例化
|——initialize(); // 方法进行初始化操作
|——startHttpServer(); // 启动HttpServer
|——httpServer = new NameNodeHttpServer(); // 通过实例化HttpServer进行启动
|——httpServer.start(); // 具体的一些启动细节:servlet等配置
|——setupServlets();
|——httpServer.start();
|——join()
现在,对上述的整个流程进行一个梳理,
- NameNode.main() 入口函数
- createNameNode() 方法通过new NameNode()进行实例化
- 实例化的时候,会通过initialize()方法进行初始化操作
- 初始化操作主要包含了启动HttpServer、加载元数据信息、启动RpcServer这三部分。后面两部分待后续篇幅进行研究。
第三步,http server服务流程图解。
Hadoop源码学习笔记之NameNode启动场景流程二:http server启动源码剖析的更多相关文章
- Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍
最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...
- Hadoop源码学习笔记之NameNode启动场景流程四:rpc server初始化及启动
老规矩,还是分三步走,分别为源码调用分析.伪代码核心梳理.调用关系图解. 一.源码调用分析 根据上篇的梳理,直接从initialize()方法着手.源码如下,部分代码的功能以及说明,已经在注释阐述了. ...
- Hadoop源码学习笔记之NameNode启动场景流程三:FSNamesystem初始化源码剖析
上篇内容分析了http server的启动代码,这篇文章继续从initialize()方法中按执行顺序进行分析.内容还是分为三大块: 一.源码调用关系分析 二.伪代码执行流程 三.代码图解 一.源码调 ...
- (三)Netty源码学习笔记之boss线程处理流程
尊重原创,转载注明出处,原文地址:http://www.cnblogs.com/cishengchongyan/p/6160194.html 本文我们将先从NioEventLoop开始来学习服务端的 ...
- Hadoop源码学习笔记之NameNode启动场景流程五:磁盘空间检查及安全模式检查
本篇内容关注NameNode启动之前,active状态和standby状态的一些后台服务及准备工作,即源码里的CommonServices.主要包括磁盘空间检查. 可用资源检查.安全模式等.依然分为三 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构
Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构 之前我们简要的看过了DataNode的main函数以及整个类的大至,现在结合前面我们研究的线程和RPC,则可以进一步 ...
- Hadoop源码学习笔记(6)——从ls命令一路解剖
Hadoop源码学习笔记(6) ——从ls命令一路解剖 Hadoop几个模块的程序我们大致有了点了解,现在我们得细看一下这个程序是如何处理命令的. 我们就从原头开始,然后一步步追查. 我们先选中ls命 ...
- Hadoop源码学习笔记(2) ——进入main函数打印包信息
Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...
随机推荐
- 关于Unity3d的Quaternion.LookRotation的学习
首先,创建两个cube GameObject物件.Origin作为原点参考.Player是我们要实验的物件.如下图所示: 创建一个脚本Quat.cs,赋给Palyer cube.脚本如下: publi ...
- 服务器编程入门(13) Linux套接字设置超时的三种方法
摘要: 本文介绍在套接字的I/O操作上设置超时的三种方法. 图片可能有点宽,看不到的童鞋可以点击图片查看完整图片.. 1 调用alarm 使用SIGALRM为connect设置超时 设置方法: ...
- 克隆对象__clone()方法
有的时候我们需要在一个项目里面,使用两个或多个一样的对象,如果你使用“new”关键字重新创建对象的话,再赋值上相同的属性,这样做比较烦琐而且也容易出错,所以要根据一个对象完全克隆出一个一模一样的对象, ...
- 点开无线显示"已连接 安全",但是点击下面无线图标却显示"无法连接internet",解决方案
管理员权限运行“命令提示符” 输入:netsh winsock reset 然后重启电脑即可
- centos7 docker 使用pipework 做虚拟机
网卡配置文件 及 bridge的静态配置 centos7 Bridge配置 [root@mon-1 ~]# cd /etc/sysconfig/network-scripts/ [root@mon- ...
- 四、并行编程 - 并行LINQ(PLINQ) 的使用。AsParallel
用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算 一.AsParallel(并行化) 就是在集合后加个AsParallel(). 例如: , ); == ); ...
- pat 5—1 求该日是该年的第几天
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 前面还是欠了一堆,慢慢补吧. 看了别人的博客才知道前面有一次圆面积的题,我上课是在干啥......... 打是打出来了,但是还是有几个蒙蔽的地方: ...
- storm-kafka
包依赖
- bzoj4403:序列统计
我好傻啊 题目 先来看看长度只能为\(n\)的情况 那么答案非常显然是\(\binom{m+n-1}{n}\) 其中\(m=R-L+1\) 因为我们要构造一个非降序列,显然可能一个数会被选择多次,组合 ...
- [19/04/19-星期五] Java的动态性_脚本(Script,脚本)引擎执行JavaScript代码
一.概念 Java脚本引擎是jdk 6.0之后的新功能. 使得Java应用程序可以通过一套固定的接口与各种脚本引擎交互,从而达到在Java平台上调用各种脚本语言的目的. Java脚本API是连接Jav ...