NameNode介绍:
NameNode管理文件系统的命名空间。
-
它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件(fsimage)和编辑日志文件(editlog)。
-
它管理block块与datanode的映射关系(Namenode启动时候块上报,保存在内存中);
-
它能接收cilent的请求,接收datanode的块报告和心跳;
具体实现的类:
-
Namenode类:启动类,管理配置等
-
Namenode server:NameNodeRPCServer(接收和处理所有rpc请求)和NameNodeHttpServer(web)
-
FSNamesystem:负责Namenode的所有逻辑,管理HDFS元数据
fsimage与editlog的作用
fsimage相当于一个快照(checkpoint)保存了最新的元数据检查点,在HDFS启动时加载fsimage的信息,包含了整个HDFS文件系统的所有目录和文件的信息,editlog主要是在NameNode已经启动情况下对HDFS进行的各种更新操作进行记录,HDFS客户端执行所有的写操作都会被记录到editlog中。(类似于redis的RBD+AOF的混合存储方式)
优势:
-
可防止fsimage过大或者频繁进行快照
-
降低Namedode压力:在Standalone模式下通过Secondary NameNode,HA模式下通过Standby Namenode,将fsimage文件和editolg文件合并成新的fsimage。
启动代码流程图
源码解析
start-dfs.sh脚本是为了启动namenode,定位到Namenode启动类中main方法
public static void main(String argv[]) throws Exception {
...
try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
//创建NN对象
NameNode namenode = createNameNode(argv, null);
if (namenode != null) {
//阻塞作用,让main线程无法结束
namenode.join();
}
} ...
}
createNameNode是重要的方法,用于构造NN对象
public static NameNode createNameNode(String argv[], Configuration conf)
throws IOException {
LOG.info("createNameNode " + Arrays.asList(argv));
//配置文件
if (conf == null)
conf = new HdfsConfiguration();
// Parse out some generic args into Configuration.
//解析
GenericOptionsParser hParser = new GenericOptionsParser(conf, argv);
argv = hParser.getRemainingArgs();
// Parse the rest, NN specific args.
StartupOption startOpt = parseArguments(argv);
...
boolean aborted = false;
//根据启动选项执行不同的方法
switch (startOpt) {
case FORMAT:
//初始化
aborted = format(conf, startOpt.getForceFormat(),startOpt.getInteractiveFormat());
case GENCLUSTERID:
case ROLLBACK:
case BOOTSTRAPSTANDBY:
case INITIALIZESHAREDEDITS:
case BACKUP:
case CHECKPOINT:
case RECOVER:
case METADATAVERSION:
case UPGRADEONLY:
default:
DefaultMetricsSystem.initialize("NameNode");
//构造NN
return new NameNode(conf);
}
}
配置NN后需要先初始化NN,进入format方法
private static boolean format(Configuration conf, boolean force,
boolean isInteractive) throws IOException {
...
FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
try {
//构建FSNamesystem用于管理NN信息
FSNamesystem fsn = new FSNamesystem(conf, fsImage);
//初始化Journal
fsImage.getEditLog().initJournalsForWrite();
}
...
fsImage.format(fsn, clusterId, force);
...
return false;
}
返回createNameNode,new NameNode(conf)构造NN对象
protected NameNode(Configuration conf, NamenodeRole role)
throws IOException {
//配置
super(conf);
// 根据配置确认是否开启了HA
String namenodeId = HAUtil.getNameNodeId(conf, nsId);
//是否启用ha
this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
//非HA -> ACTIVE_STATE
state = createHAState(getStartupOption(conf));
//初始化
initialize(getConf());
//初始化完成后, Namenode进入Standby状态
//在这里会开启StandbyCheckpointer里面的checkpointer 线程. 定时合并&处理images文件
state.prepareToEnterState(haContext);
state.enterState(haContext);
}
initialize是重要方法,会初始化httpserver、rpserver,构造FSNamesystem用于管理文件系统
进入initialize(getConf())方法
protected void initialize(Configuration conf) throws IOException {
//配置
//构造JvmPauseMonitor对象, 并启动
pauseMonitor = new JvmPauseMonitor();
pauseMonitor.init(conf);
pauseMonitor.start();
metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
//启动HTTP服务
if (NamenodeRole.NAMENODE == role) {
startHttpServer(conf);
}
// 初始化FSNamesystem
// NameNode将对文件系统的管理都委托给了FSNamesystem对象,
// NameNode会调用FSNamesystem.loadFromDisk()创建FSNamesystem对象。
// FSNamesystem.loadFromDisk()首先调用构造方法构造FSNamesystem对象,
// 然后将fsimage以及editlog文件加载到命名空间中。
loadNamesystem(conf);
//创建RPC服务/创建多个协议/创建serviceRpcServer和clientRpcServer
rpcServer = createRpcServer(conf);
//启动公共服务/资源检查/安全模式
startCommonServices(conf);
//启动计时器定期将NameNode度量写入日志文件。此行为可由配置禁用。
startMetricsLogger(conf);
}
void startCommonServices(Configuration conf, HAContext haContext) throws IOException {
//NameNode资源检查 通过core-site.xml hdfs-site.xml两个文件获取元数据存储位置
//需要检查三个目录,因为这三个目录都涉及到了元数据
//NameNode的两个目录:存储fsiamge的目录,存储editlog的目录。但是一般情况下,或者默认情况这两个使用的是同一个目录。
//Journlanode里面有也有存储元数据的目录。高可用的模式了
//获取到了要检查的目录
nnResourceChecker = new NameNodeResourceChecker(conf);
//检查是否有可用资源
checkAvailableResources();
//安全模式判断
//获取正常的block块数x
long completeBlocksTotal = getCompleteBlocksTotal();
prog.setTotal(Phase.SAFEMODE, STEP_AWAITING_REPORTED_BLOCKS,
completeBlocksTotal);
//启动重要服务
blockManager.activate(conf, completeBlocksTotal);
}