在安装 hadoop 的时候,必须对 hdfs 的 Namenode 进行格式化操作。本文主要介绍格式化操作
格式化命令如下
bin/hdfs namenode -format
入口
Namenode 的格式化操作是:org.apache.hadoop.hdfs.server.namenode.NameNode
/***/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);//调用createNameNode()方法创建NameNode对象NameNode namenode = createNameNode(argv, null);if (namenode != null) {//等待Namenode RPC服务结束namenode.join();}} catch (Throwable e) {LOG.error("Failed to start namenode.", e);//出现异常则直接退出执行terminate(1, e);}}
通过 main 入口的方法,我们可以知道接下来是调用 createNameNode 方法。然后根据传入的参数不同执行不同的代码片段。我们主要是看格式化操作,所以关注一下 FORMAT 这个代码片段就可以了
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);if (startOpt == null) {printUsage(System.err);return null;}setStartupOption(conf, startOpt);boolean aborted = false;//根据启动选项调用对应的方法执行操作switch (startOpt) {//格式化当前Namenode, 调用format()方法执行格式化操作case FORMAT:aborted = format(conf, startOpt.getForceFormat(),startOpt.getInteractiveFormat());terminate(aborted ? 1 : 0);return null; // avoid javac warningcase GENCLUSTERID:// 代码略...//回滚上一次升级, 调用doRollback()方法执行回滚操作。case ROLLBACK:// 代码略...// 拷贝Active Namenode的最新命名空间数据到StandbyNamenode,// 调用BootstrapStandby.run()方法执行操作case BOOTSTRAPSTANDBY:// 代码略...//初始化editlog的共享存储空间, 并从Active//Namenode中拷贝足够的editlog数据, 使得Standby节点能够顺利启动。 这里调用//了静态方法initializeSharedEdits()执行操作case INITIALIZESHAREDEDITS:// 代码略...case BACKUP://启动checkpoint节点, 也是直接构造BackupNode对象并返回。case CHECKPOINT:// 代码略...//恢复损坏的元数据以及文件系统, 这里调用了doRecovery()方法执行操作case RECOVER:// 代码略...//确认配置文件夹存在, 并且打印fsimage文件和文件系统的元数据版本case METADATAVERSION:// 代码略...//升级Namenode, 升级完成后关闭Namenode。case UPGRADEONLY:// 代码略...//在默认情况下直接构造NameNode对象并返回default:// 初始化 度量服务DefaultMetricsSystem.initialize("NameNode");// 构建NameNodereturn new NameNode(conf);}}
格式化操作format
生成一个集群id,然后构建一个FSImage
clusterId:规则 CID-UUID 如:CID-d5e21420-46b8-41fb-acc7-8562be611472
// 构建 FSImageFSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
然后根据 FSImage 构建和配置文件构建 FSNamesystem,最后再调用
fsImage.format(fsn, clusterId, force);
这个进行初始化操作,生成文件
/*** Verify that configured directories exist, then* Interactively confirm that formatting is desired* for each existing directory and format them.** @param conf configuration to use* @param force if true, format regardless of whether dirs exist* @return true if formatting was aborted, false otherwise* @throws IOException*/private static boolean format(Configuration conf, boolean force,boolean isInteractive) throws IOException {// nsId = nullString nsId = DFSUtil.getNamenodeNameServiceId(conf);// namenodeId = nullString namenodeId = HAUtil.getNameNodeId(conf, nsId);initializeGenericKeys(conf, nsId, namenodeId);//读取配置dfs.namenode.support.allow.format namenode是否可以格式化: 默认truecheckAllowFormat(conf);if (UserGroupInformation.isSecurityEnabled()) {InetSocketAddress socAddr = DFSUtilClient.getNNAddress(conf);SecurityUtil.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY,DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, socAddr.getHostName());}Collection<URI> nameDirsToFormat = FSNamesystem.getNamespaceDirs(conf);// list<URI> 0 : file:/tools/hadoop-3.2.1/data/namenodeList<URI> sharedDirs = FSNamesystem.getSharedEditsDirs(conf);List<URI> dirsToPrompt = new ArrayList<URI>();dirsToPrompt.addAll(nameDirsToFormat);dirsToPrompt.addAll(sharedDirs);// list<URI> 0 : file:/tools/hadoop-3.2.1/data/namenodeList<URI> editDirsToFormat = FSNamesystem.getNamespaceEditsDirs(conf);// if clusterID is not provided - see if you can find the current oneString clusterId = StartupOption.FORMAT.getClusterId();if(clusterId == null || clusterId.equals("")) {// Generate a new cluster id// 生成新的id 举例: CID-UUID ==> CID-d5e21420-46b8-41fb-acc7-8562be611472clusterId = NNStorage.newClusterID();}System.out.println("Formatting using clusterid: " + clusterId);// 构建 FSImageFSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);//构建 FSNamesystemtry {FSNamesystem fsn = new FSNamesystem(conf, fsImage);fsImage.getEditLog().initJournalsForWrite();// Abort NameNode format if reformat is disabled and if// meta-dir already existsif (conf.getBoolean(DFSConfigKeys.DFS_REFORMAT_DISABLED,DFSConfigKeys.DFS_REFORMAT_DISABLED_DEFAULT)) {force = false;isInteractive = false;for (StorageDirectory sd : fsImage.storage.dirIterable(null)) {if (sd.hasSomeData()) {throw new NameNodeFormatException("NameNode format aborted as reformat is disabled for "+ "this cluster.");}}}if (!fsImage.confirmFormat(force, isInteractive)) {return true; // aborted}fsImage.format(fsn, clusterId, force);} catch (IOException ioe) {LOG.warn("Encountered exception during format: ", ioe);fsImage.close();throw ioe;}return false;}
格式化后生成的文件和内容
格式化之后,会在配置 namenode 的目录生成一个 current 文件夹,里面会有四个文件
VERSION 记录版本信息 fsimage_0000000000000000000.md5 记录fsimage_0000000000000000000对应的md5 fsimage_0000000000000000000 namenode对应的fsimage文件 seen_txid 事务标识
-rw-r--r--@ 1 sysadmin staff 218 9 6 22:11 VERSION-rw-r--r--@ 1 sysadmin staff 401 9 6 22:13 fsimage_0000000000000000000-rw-r--r-- 1 sysadmin staff 62 9 6 22:13 fsimage_0000000000000000000.md5-rw-r--r--@ 1 sysadmin staff 2 9 6 22:11 seen_txid
Version 文件
#Sun Sep 06 22:11:02 CST 2020namespaceID=1147175932clusterID=CID-d5e21420-46b8-41fb-acc7-8562be611472cTime=1599401184918storageType=NAME_NODEblockpoolID=BP-1598486647-192.168.8.156-1599401184918layoutVersion=-65
Seen_txid: 存储一个数字0
fsimage_0000000000000000000.md5 记录 fsimage_0000000000000000000 对应的 md5 值
fsimage_0000000000000000000:这里面的内容比较繁琐主要包含以下信息:
- 保存命名空间信息
- 保存 ErasureCoding 信息
- 保存命名空间中的inode信息
- 保存快照信息
- 保存安全信息
- 保存缓存信息
- 保存StringTable
