hadoop2.5.2学习及实践笔记(四)—— namenode启动过程源码概览
对namenode启动时的相关操作及相关类有一个大体了解,后续深入研究时,再对本文进行补充
>实现类
HDFS启动脚本为$HADOOP_HOME/sbin/start-dfs.sh,查看start-dfs.sh可以看出,namenode是通过bin/hdfs命令来启动
- $ vi start-dfs.sh
- # namenodes
- NAMENODES=$($HADOOP_PREFIX/bin/hdfs getconf -namenodes)
- echo "Starting namenodes on [$NAMENODES]"
- "$HADOOP_PREFIX/sbin/hadoop-daemons.sh" \
- --config "$HADOOP_CONF_DIR" \
- --hostnames "$NAMENODES" \
- --script "$bin/hdfs" start namenode $nameStartOpt
- #---------------------------------------------------------
查看$HADOOP_HOME/bin/hdfs,可以找到namenode启动所调用的java类。
- $ vi bin/hdfs:
- if [ "$COMMAND" = "namenode" ] ; then
- CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'
- HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"
>源码查看
按照前文hadoop2.5.2学习及实践笔记(二)——编译源代码及导入源码至eclipse步骤,源码已经导入到eclipse中,快捷键ctrl+shift+R搜索并打开NameNode.java查看源码
NameNode类中有一个静态代码块,表示在加载器加载NameNode类过程中的准备阶段,就会执行代码块中的代码。HdfsConfiguration的init()方法的方法体是空的,这里的作用是触发对HdfsConfiguration的主动调用,从而保证在执行NameNode类相关调用时,如果HdfsConfiguration类没有被加载和初始化,先触发HdfsConfiguration的初始化过程。
- //org.apache.hadoop.hdfs.server.namenode.NameNode.java
- static{
- //HdfsConfiguration类init()方法:public static void init() {}
- HdfsConfiguration.init();
- }
查看其main方法,可以看出namenode相关操作的主要入口方法是createNameNode(String argv[], Configuration conf)方法。
- //org.apache.hadoop.hdfs.server.namenode.NameNode.java
- public static void main(String argv[]) throws Exception {
- if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
- System.exit(0);
- }
- try {
- //打印namenode启动或关闭日志信息
- StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
- //namenode相关主要操作
- NameNode namenode = createNameNode(argv, null);
- if (namenode != null) {
- //向客户端和datanode提供RPC服务,直到RPC服务器结束运行
- namenode.join();
- }
- } catch (Throwable e) {
- LOG.fatal("Exception in namenode join", e);
- terminate(1, e);
- }
- }
createNameNode方法中通过一个switch语句对不同的命令执行不同的操作。比如搭建环境时格式化文件系统时的操作,可以查看FORMAT分支。
- //org.apache.hadoop.hdfs.server.namenode.NameNode.java
- public static NameNode createNameNode(String argv[], Configuration conf)
- throws IOException {
- LOG.info("createNameNode " + Arrays.asList(argv));
- if (conf == null)
- conf = new HdfsConfiguration();
- //参数为空时默认: -regular
- StartupOption startOpt = parseArguments(argv);
- if (startOpt == null) {
- printUsage(System.err);
- return null;
- }
- setStartupOption(conf, startOpt);
- switch (startOpt) {
- case FORMAT: {//格式化文件系统,伪分布式环境搭建时调用过namenode -format命令
- boolean aborted = format(conf, startOpt.getForceFormat(),
- startOpt.getInteractiveFormat());
- terminate(aborted ? 1 : 0);
- return null; // avoid javac warning
- }
- case GENCLUSTERID: {
- System.err.println("Generating new cluster id:");
- System.out.println(NNStorage.newClusterID());
- terminate(0);
- return null;
- }
- case FINALIZE: {
- System.err.println("Use of the argument '" + StartupOption.FINALIZE +
- "' is no longer supported. To finalize an upgrade, start the NN " +
- " and then run `hdfs dfsadmin -finalizeUpgrade'");
- terminate(1);
- return null; // avoid javac warning
- }
- case ROLLBACK: {
- boolean aborted = doRollback(conf, true);
- terminate(aborted ? 1 : 0);
- return null; // avoid warning
- }
- case BOOTSTRAPSTANDBY: {
- String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);
- int rc = BootstrapStandby.run(toolArgs, conf);
- terminate(rc);
- return null; // avoid warning
- }
- case INITIALIZESHAREDEDITS: {
- boolean aborted = initializeSharedEdits(conf,
- startOpt.getForceFormat(),
- startOpt.getInteractiveFormat());
- terminate(aborted ? 1 : 0);
- return null; // avoid warning
- }
- case BACKUP:
- case CHECKPOINT: {//backupnode和checkpointnode启动
- NamenodeRole role = startOpt.toNodeRole();
- DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
- //backupnode继承NameNode类,代码最终执行的还是NameNode的构造方法
- return new BackupNode(conf, role);
- }
- case RECOVER: {
- NameNode.doRecovery(startOpt, conf);
- return null;
- }
- case METADATAVERSION: {
- printMetadataVersion(conf);
- terminate(0);
- return null; // avoid javac warning
- }
- default: {
- DefaultMetricsSystem.initialize("NameNode");
- //启动时startOpt=“-regular”,代码执行default分支,通过构造函数返回一个namenode实例
- return new NameNode(conf);
- }
- }
- }
namenode的构造方法
- //org.apache.hadoop.hdfs.server.namenode.NameNode.java
- public NameNode(Configuration conf) throws IOException {
- this(conf, NamenodeRole.NAMENODE);
- }
- protected NameNode(Configuration conf, NamenodeRole role)
- throws IOException {
- this.conf = conf;
- this.role = role;
- //获取fs.defaultFS,设置namenode地址
- setClientNamenodeAddress(conf);
- String nsId = getNameServiceId(conf);
- String namenodeId = HAUtil.getNameNodeId(conf, nsId);
- //是否启用HA
- this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
- //HA状态:启用/备用
- state = createHAState(getStartupOption(conf));
- //读取dfs.ha.allow.stale.reads,设置namenode在备用状态时是否允许读操作,默认为false
- this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
- this.haContext = createHAContext();
- try {
- //联邦环境下,使用该方法配置一系列使用一个逻辑上的nsId组合在一起的namenode
- initializeGenericKeys(conf, nsId, namenodeId);
- //namenode初始化
- initialize(conf);
- try {
- haContext.writeLock();
- state.prepareToEnterState(haContext);
- //namenode进入相应状态:active state/backup state/standby state
- state.enterState(haContext);
- } finally {
- haContext.writeUnlock();
- }
- } catch (IOException e) {
- this.stop();
- throw e;
- } catch (HadoopIllegalArgumentException e) {
- this.stop();
- throw e;
- }
- }
namenode初始化方法代码
- //org.apache.hadoop.hdfs.server.namenode.NameNode.java
- 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);
- }
- }
- //设置权限,根据hadoop.security.authentication获取认证方式及规则
- UserGroupInformation.setConfiguration(conf);
- //登录:如果认证方式为simple则退出该方法
- //否则调用UserGroupInformation.loginUserFromKeytab进行登陆,登陆使用dfs.namenode.kerberos.principal作为用户名
- loginAsNameNodeUser(conf);
- //初始化度量系统,用于度量namenode服务状态
- NameNode.initMetrics(conf, this.getRole());
- StartupProgressMetrics.register(startupProgress);
- if (NamenodeRole.NAMENODE == role) {
- //启动http服务器
- startHttpServer(conf);
- }
- //根据命令对命名空间进行操作,如:前文所述启动时加载本地命名空间镜像和应用编辑日志,在内存中建立命名空间的映像
- loadNamesystem(conf);
- //创建RPC服务器
- 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服务和namenode的插件程序启动
- startCommonServices(conf);
- }
loadNamesystem(Configuration conf)方法调用FSNamesystem类的loadFromDisk(Configuration conf)。前文提到的,namenode启动时从本地文件系统加载镜像并重做编辑日志,都在此方法中实现。
- //org.apache.hadoop.hdfs.server.namenode.FSNamesystem.java
- static FSNamesystem loadFromDisk(Configuration conf) throws IOException {
- //必须的编辑日志目录检查
- checkConfiguration(conf);
- //设在NNStorage,并初始化编辑日志目录。NNStorage主要功能是管理namenode使用的存储目录
- FSImage fsImage = new FSImage(conf,
- FSNamesystem.getNamespaceDirs(conf),
- FSNamesystem.getNamespaceEditsDirs(conf));
- //根据指定的镜像创建FSNamesystem对象
- FSNamesystem namesystem = new FSNamesystem(conf, fsImage, false);
- StartupOption startOpt = NameNode.getStartupOption(conf);
if (startOpt == StartupOption.RECOVER) {- namesystem.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
- }
- long loadStart = now();
- try {
- //加载镜像、重做编辑日志,并打开一个新编辑文件都在此方法中
- namesystem.loadFSImage(startOpt);
- } catch (IOException ioe) {
- LOG.warn("Encountered exception loading fsimage", ioe);
- fsImage.close();
- throw ioe;
- }
- long timeTakenToLoadFSImage = now() - loadStart;
- LOG.info("Finished loading FSImage in " + timeTakenToLoadFSImage + " msecs");
- NameNodeMetrics nnMetrics = NameNode.getNameNodeMetrics();
- if (nnMetrics != null) {
- nnMetrics.setFsImageLoadTime((int) timeTakenToLoadFSImage);
- }
- return namesystem;
- }
- private void loadFSImage(StartupOption startOpt) throws IOException {
- final FSImage fsImage = getFSImage();
- // format before starting up if requested
- if (startOpt == StartupOption.FORMAT) {
- fsImage.format(this, fsImage.getStorage().determineClusterId());// reuse current id
- startOpt = StartupOption.REGULAR;
- }
- boolean success = false;
- writeLock();
- try {
- // We shouldn't be calling saveNamespace if we've come up in standby state.
- MetaRecoveryContext recovery = startOpt.createRecoveryContext();
- final boolean staleImage
- = fsImage.recoverTransitionRead(startOpt, this, recovery);
- if (RollingUpgradeStartupOption.ROLLBACK.matches(startOpt)) {
- rollingUpgradeInfo = null;
- }
- final boolean needToSave = staleImage && !haEnabled && !isRollingUpgrade();
- LOG.info("Need to save fs image? " + needToSave
- + " (staleImage=" + staleImage + ", haEnabled=" + haEnabled
- + ", isRollingUpgrade=" + isRollingUpgrade() + ")");
- if (needToSave) {
- fsImage.saveNamespace(this);
- } else {
- // No need to save, so mark the phase done.
- StartupProgress prog = NameNode.getStartupProgress();
- prog.beginPhase(Phase.SAVING_CHECKPOINT);
- prog.endPhase(Phase.SAVING_CHECKPOINT);
- }
- // This will start a new log segment and write to the seen_txid file, so
- // we shouldn't do it when coming up in standby state
- if (!haEnabled || (haEnabled && startOpt == StartupOption.UPGRADE)) {
- fsImage.openEditLogForWrite();
- }
- success = true;
- } finally {
- if (!success) {
- fsImage.close();
- }
- writeUnlock();
- }
- imageLoadComplete();
- }
hadoop2.5.2学习及实践笔记(四)—— namenode启动过程源码概览的更多相关文章
- hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse
生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...
- hadoop2.5.2学习及实践笔记(五)—— HDFS shell命令行常见操作
附:HDFS shell guide文档地址 http://hadoop.apache.org/docs/r2.5.2/hadoop-project-dist/hadoop-common/FileSy ...
- hadoop2.5.2学习及实践笔记(三)—— HDFS概念及体系结构
注:文中涉及的文件路径或配置文件中属性名称是针对hadoop2.X系列,相对于之前版本,可能有改动. 附: HDFS用户指南官方介绍: http://hadoop.apache.org/docs/r2 ...
- hadoop2.5.2学习及实践笔记(六)—— Hadoop文件系统及其java接口
文件系统概述 org.apache.hadoop.fs.FileSystem是hadoop的抽象文件系统,为不同的数据访问提供了统一的接口,并提供了大量具体文件系统的实现,满足hadoop上各种数据访 ...
- hadoop2.5.2学习及实践笔记(一)—— 伪分布式学习环境搭建
软件 工具:vmware 10 系统:centOS 6.5 64位 Apache Hadoop: 2.5.2 64位 Jdk: 1.7.0_75 64位 安装规划 /opt/softwares ...
- kafka原理和实践(四)spring-kafka消费者源码
系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...
- Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
- 【后台管理系统】—— Ant Design Pro入门学习&项目实践笔记(三)
前言:前一篇记录了[后台管理系统]目前进展开发中遇到的一些应用点,这一篇会梳理一些自己学习Ant Design Pro源码的功能点.附:Ant Design Pro 在线预览地址. Dashboard ...
- Hadoop源码学习笔记之NameNode启动场景流程四:rpc server初始化及启动
老规矩,还是分三步走,分别为源码调用分析.伪代码核心梳理.调用关系图解. 一.源码调用分析 根据上篇的梳理,直接从initialize()方法着手.源码如下,部分代码的功能以及说明,已经在注释阐述了. ...
随机推荐
- 【杂题总汇】Codeforces-67A Partial Teacher
[Codeforces-67A]Partial Teacher 上周刷了一大堆小紫薯的动态规划的题
- ELK+kafka日志处理
此次使用kafka代替redis,elk集群搭建过程请参考:https://www.cnblogs.com/dmjx/p/9120474.html kafka名词解释: 1.话题(Topic):是特定 ...
- IntelliJ IDEA 12 创建Web项目 教程 超详细版【转】
IntelliJ IDEA 12 新版本发布 第一时间去官网看了下 黑色的主题 很给力 大体使用了下 对于一开始就是用eclipse的童鞋们 估计很难从eclipse中走出来 当然 我也很艰难的走 ...
- SQLSERVER 数据库恢复挂起的解决办法
如果你的数据库还处于挂起状态,请把我下面代码的test改为你的库名,然后执行完,刷新就正常了: USE masterGOALTER DATABASE test SET SINGLE_USERGOALT ...
- 【PHP项目】$_SEVER详解
$_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言 $_SERVER['REMOTE_ADDR'] //当前用户 IP . $_SERVER['REMOTE_HOST'] ...
- phpstorm 安装XeDbug
第一步:根据phpinfo()下载相对应的Xdebug插件,Xdebug下载路径https://xdebug.org/download.php 第二步:将下载好的Xdebug放到 G:\Service ...
- jQuery检测判断复选框是否被选中了的几种方法
方法一:if ($("#checkbox-id")get(0).checked) { // do something} 方法二:if($('#checkbox-id').is ...
- 学习python第十二天,函数4 生成器generator和迭代器Iterator
在Python中,这种一边循环一边计算的机制,称为生成器:generator 要创建一个generator,有很多种方法.第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个genera ...
- Pandas 数值计算和统计基础
1.(1) # 基本参数:axis.skipna import numpy as np import pandas as pd df = pd.DataFrame({'key1':[4,5,3,np. ...
- H2数据库使用
H2数据库使用 H2数据库介绍 H2的优势: 1.h2采用纯Java编写,因此不受平台的限制. 2.h2只有一个jar文件,十分适合作为嵌入式数据库试用. 3.性能和功能的优势 H2和各数据库特征比较 ...