HDFS------hadoop namenode -format
2011-09-02 14:07
381 查看
集群搭建好了以后,通常我们会输入命令:/bin/hadoop namenode -format对hdfs进行格式化,那究竟格式化都做些什么具体的工作呢,怀着好奇心到源码里一探究竟。
首先从这行命令/bin/hadoop namenode -format 可以判断出会调用NameNode的main方法,到源码里一看,果然如此:
在org.apache.hadoop.hdfs.server.namenode包有个类NameNode,它的main方法如下:
---------------------------------------------------------------------------------------------------------------------------------
public static void main(String argv[]) throws Exception {
try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
NameNode namenode = createNameNode(argv, null);
if (namenode != null)
namenode.join();
} catch (Throwable e) {
LOG.error(StringUtils.stringifyException(e));
System.exit(-1);
}
}
---------------------------------------------------------------------------------------------------------------------------------
其中 NameNode namenode = createNameNode(argv, null);用来创建namenode,进入方法中:
public static NameNode createNameNode(String argv[],
Configuration conf) throws IOException {
if (conf == null)
conf = new Configuration();
StartupOption startOpt = parseArguments(argv);
if (startOpt == null) {
printUsage();
return null;
}
setStartupOption(conf, startOpt);
switch (startOpt) {
case FORMAT:
boolean aborted = format(conf, true);
System.exit(aborted ? 1 : 0);
case FINALIZE:
aborted = finalize(conf, true);
System.exit(aborted ? 1 : 0);
default:
}
DefaultMetricsSystem.initialize("NameNode");
NameNode namenode = new NameNode(conf);
return namenode;
}
其中FORMAT即为我们在命令行输入的-format,此时会调用format方法,下面集中看这个方法做了哪些工作:
===========================================================================================
private static boolean format(Configuration conf,
boolean isConfirmationNeeded
) throws IOException {
/******dirsToFormat是我们在配置文件中dfs.name.dir的value,这个value默认是在/tmp/hadoop/dfs/name目录下******/
Collection<File> dirsToFormat = FSNamesystem.getNamespaceDirs(conf);
Collection<File> editDirsToFormat =
FSNamesystem.getNamespaceEditsDirs(conf);
for(Iterator<File> it = dirsToFormat.iterator(); it.hasNext();) {
File curDir = it.next();
if (!curDir.exists())
continue;
if (isConfirmationNeeded) {
System.err.print("Re-format filesystem in " + curDir +" ? (Y or N) ");
if (!(System.in.read() == 'Y')) {
System.err.println("Format aborted in "+ curDir);
return true;
}
while(System.in.read() != '\n'); // discard the enter-key
}
}
/*******构建一个FSNamesystem,构建一个FSImage,然后把FSImage传给了FSNamesystem,其它的先不要管,我们先来看下
*******FSImage的构建。
FSNamesystem nsys = new FSNamesystem(new FSImage(dirsToFormat,
editDirsToFormat), conf);
nsys.dir.fsImage.format();
return false;
}
===========================================================================================
FSImage里做的工作很简单就是绑定dirsToFormat(默认为/tmp/hadoop/dfs/name)和editDirsToFormat(默认为/tmp/hadoop/dfs/name)
在FSImage的构造函数里会调用setStorageDirectories方法,它的作用是将dfs.name.dir和dfs.name.edits.dir这两个变量所设置的目录去重,然后将其目录以及目录的类型NameNodeDirType设定到FSImage中去。
回到nsys.dir.fsImage.format();这行代码其实调用的就是我们刚刚创建的FSImage,它的format方法。format的主要工作也是由这个方法来完成的。
====================================================================================================================
public void format() throws IOException {
this.layoutVersion = FSConstants.LAYOUT_VERSION;
this.namespaceID = newNamespaceID();
this.cTime = 0L;
this.checkpointTime = FSNamesystem.now();
for (Iterator<StorageDirectory> it =
dirIterator(); it.hasNext();) {
StorageDirectory sd = it.next();
format(sd);
}
}
======================================================================================================================
format方法里首先把设置一些fsimage的变量,例如:layoutVersion,namespaceID,time,checkpointtime等,然后遍历storageDirs,依次进行format
/** Create new dfs name directory. Caution: this destroys all files
* in this filesystem. */
void format(StorageDirectory sd) throws IOException {
sd.clearDirectory(); // create currrent dir
sd.lock();
try {
saveCurrent(sd);
} finally {
sd.unlock();
}
LOG.info("Storage directory " + sd.getRoot()
+ " has been successfully formatted.");
}
可以看到,首先将current目录删除(如果有的话),然后调用 saveCurrent(sd);
protected void saveCurrent(StorageDirectory sd) throws IOException {
File curDir = sd.getCurrentDir();
NameNodeDirType dirType = (NameNodeDirType)sd.getStorageDirType();
// save new image or new edits
if (!curDir.exists() && !curDir.mkdir())
throw new IOException("Cannot create directory " + curDir);
if (dirType.isOfType(NameNodeDirType.IMAGE))
saveFSImage(getImageFile(sd, NameNodeFile.IMAGE));
if (dirType.isOfType(NameNodeDirType.EDITS))
editLog.createEditLogFile(getImageFile(sd, NameNodeFile.EDITS));
// write version and time files
sd.write();
}
在saveCurrent方法中首先获取这个storageDir的current目录,如果它的current不存在则先创建current,然后根据storageDir的type,来决定创建fsimage文件或者使edits文件。最后是创建version文件和time文件。
下面一张截图是我从自己的测试机上截取下来的,可以看到current目录下面的四个文件:
======================================================================================
那这四个文件里面具体都写的是哪些数据呢,再此怀着好奇心,去看看到底写的什么,先看fsimage这个文件,
void saveFSImage(File newFile) throws IOException {
FSNamesystem fsNamesys = FSNamesystem.getFSNamesystem();
FSDirectory fsDir = fsNamesys.dir;
long startTime = FSNamesystem.now();
//
// Write out data
//
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(newFile)));
try {
out.writeInt(FSConstants.LAYOUT_VERSION); =============写入布局版本id
out.writeInt(namespaceID); =============写入命名空间id
out.writeLong(fsDir.rootDir.numItemsInTree()); =============写入根目录(这里指的是dfs.name.dir)
out.writeLong(fsNamesys.getGenerationStamp()); =============写入创建文件系统时间戳
byte[] byteStore = new byte[4*FSConstants.MAX_PATH_LENGTH];
ByteBuffer strbuf = ByteBuffer.wrap(byteStore);
// save the root
saveINode2Image(strbuf, fsDir.rootDir, out); =============写入文件或者目录的元数据信息,包括复制级别,修改时间,访问时间,块信息等
// save the rest of the nodes
saveImage(strbuf, 0, fsDir.rootDir, out);
fsNamesys.saveFilesUnderConstruction(out);
fsNamesys.saveSecretManagerState(out);
strbuf = null;
} finally {
out.close();
}
LOG.info("Image file of size " + newFile.length() + " saved in "
+ (FSNamesystem.now() - startTime)/1000 + " seconds.");
}
=========================================================
可以看到,采用了递归调用的方式(saveINode2Image,saveImage)将root目录树结构存储了起来。
最后来看下saveINode2Image这个方法:
private static void saveINode2Image(ByteBuffer name,
INode node,
DataOutputStream out) throws IOException {
int nameLen = name.position();
out.writeShort(nameLen);
out.write(name.array(), name.arrayOffset(), nameLen);
if (!node.isDirectory()) { // write file inode
INodeFile fileINode = (INodeFile)node;
out.writeShort(fileINode.getReplication());
out.writeLong(fileINode.getModificationTime());
out.writeLong(fileINode.getAccessTime());
out.writeLong(fileINode.getPreferredBlockSize());
Block[] blocks = fileINode.getBlocks();
out.writeInt(blocks.length);
for (Block blk : blocks)
blk.write(out);
FILE_PERM.fromShort(fileINode.getFsPermissionShort());
PermissionStatus.write(out, fileINode.getUserName(),
fileINode.getGroupName(),
FILE_PERM);
} else { // write directory inode
out.writeShort(0); // replication
out.writeLong(node.getModificationTime());
out.writeLong(0); // access time
out.writeLong(0); // preferred block size
out.writeInt(-1); // # of blocks
out.writeLong(node.getNsQuota());
out.writeLong(node.getDsQuota());
FILE_PERM.fromShort(node.getFsPermissionShort());
PermissionStatus.write(out, node.getUserName(),
node.getGroupName(),
FILE_PERM);
}
}
这个方法很明显,分为文件和目录两个部分,如果使文件的话,记录的信息包括文件的块大小,一个文件包括哪些块(块id,块的数量等),如果是目录,大多属性都设置为0
首先从这行命令/bin/hadoop namenode -format 可以判断出会调用NameNode的main方法,到源码里一看,果然如此:
在org.apache.hadoop.hdfs.server.namenode包有个类NameNode,它的main方法如下:
---------------------------------------------------------------------------------------------------------------------------------
public static void main(String argv[]) throws Exception {
try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
NameNode namenode = createNameNode(argv, null);
if (namenode != null)
namenode.join();
} catch (Throwable e) {
LOG.error(StringUtils.stringifyException(e));
System.exit(-1);
}
}
---------------------------------------------------------------------------------------------------------------------------------
其中 NameNode namenode = createNameNode(argv, null);用来创建namenode,进入方法中:
public static NameNode createNameNode(String argv[],
Configuration conf) throws IOException {
if (conf == null)
conf = new Configuration();
StartupOption startOpt = parseArguments(argv);
if (startOpt == null) {
printUsage();
return null;
}
setStartupOption(conf, startOpt);
switch (startOpt) {
case FORMAT:
boolean aborted = format(conf, true);
System.exit(aborted ? 1 : 0);
case FINALIZE:
aborted = finalize(conf, true);
System.exit(aborted ? 1 : 0);
default:
}
DefaultMetricsSystem.initialize("NameNode");
NameNode namenode = new NameNode(conf);
return namenode;
}
其中FORMAT即为我们在命令行输入的-format,此时会调用format方法,下面集中看这个方法做了哪些工作:
===========================================================================================
private static boolean format(Configuration conf,
boolean isConfirmationNeeded
) throws IOException {
/******dirsToFormat是我们在配置文件中dfs.name.dir的value,这个value默认是在/tmp/hadoop/dfs/name目录下******/
Collection<File> dirsToFormat = FSNamesystem.getNamespaceDirs(conf);
Collection<File> editDirsToFormat =
FSNamesystem.getNamespaceEditsDirs(conf);
for(Iterator<File> it = dirsToFormat.iterator(); it.hasNext();) {
File curDir = it.next();
if (!curDir.exists())
continue;
if (isConfirmationNeeded) {
System.err.print("Re-format filesystem in " + curDir +" ? (Y or N) ");
if (!(System.in.read() == 'Y')) {
System.err.println("Format aborted in "+ curDir);
return true;
}
while(System.in.read() != '\n'); // discard the enter-key
}
}
/*******构建一个FSNamesystem,构建一个FSImage,然后把FSImage传给了FSNamesystem,其它的先不要管,我们先来看下
*******FSImage的构建。
FSNamesystem nsys = new FSNamesystem(new FSImage(dirsToFormat,
editDirsToFormat), conf);
nsys.dir.fsImage.format();
return false;
}
===========================================================================================
FSImage里做的工作很简单就是绑定dirsToFormat(默认为/tmp/hadoop/dfs/name)和editDirsToFormat(默认为/tmp/hadoop/dfs/name)
在FSImage的构造函数里会调用setStorageDirectories方法,它的作用是将dfs.name.dir和dfs.name.edits.dir这两个变量所设置的目录去重,然后将其目录以及目录的类型NameNodeDirType设定到FSImage中去。
回到nsys.dir.fsImage.format();这行代码其实调用的就是我们刚刚创建的FSImage,它的format方法。format的主要工作也是由这个方法来完成的。
====================================================================================================================
public void format() throws IOException {
this.layoutVersion = FSConstants.LAYOUT_VERSION;
this.namespaceID = newNamespaceID();
this.cTime = 0L;
this.checkpointTime = FSNamesystem.now();
for (Iterator<StorageDirectory> it =
dirIterator(); it.hasNext();) {
StorageDirectory sd = it.next();
format(sd);
}
}
======================================================================================================================
format方法里首先把设置一些fsimage的变量,例如:layoutVersion,namespaceID,time,checkpointtime等,然后遍历storageDirs,依次进行format
/** Create new dfs name directory. Caution: this destroys all files
* in this filesystem. */
void format(StorageDirectory sd) throws IOException {
sd.clearDirectory(); // create currrent dir
sd.lock();
try {
saveCurrent(sd);
} finally {
sd.unlock();
}
LOG.info("Storage directory " + sd.getRoot()
+ " has been successfully formatted.");
}
可以看到,首先将current目录删除(如果有的话),然后调用 saveCurrent(sd);
protected void saveCurrent(StorageDirectory sd) throws IOException {
File curDir = sd.getCurrentDir();
NameNodeDirType dirType = (NameNodeDirType)sd.getStorageDirType();
// save new image or new edits
if (!curDir.exists() && !curDir.mkdir())
throw new IOException("Cannot create directory " + curDir);
if (dirType.isOfType(NameNodeDirType.IMAGE))
saveFSImage(getImageFile(sd, NameNodeFile.IMAGE));
if (dirType.isOfType(NameNodeDirType.EDITS))
editLog.createEditLogFile(getImageFile(sd, NameNodeFile.EDITS));
// write version and time files
sd.write();
}
在saveCurrent方法中首先获取这个storageDir的current目录,如果它的current不存在则先创建current,然后根据storageDir的type,来决定创建fsimage文件或者使edits文件。最后是创建version文件和time文件。
下面一张截图是我从自己的测试机上截取下来的,可以看到current目录下面的四个文件:
======================================================================================
那这四个文件里面具体都写的是哪些数据呢,再此怀着好奇心,去看看到底写的什么,先看fsimage这个文件,
void saveFSImage(File newFile) throws IOException {
FSNamesystem fsNamesys = FSNamesystem.getFSNamesystem();
FSDirectory fsDir = fsNamesys.dir;
long startTime = FSNamesystem.now();
//
// Write out data
//
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(newFile)));
try {
out.writeInt(FSConstants.LAYOUT_VERSION); =============写入布局版本id
out.writeInt(namespaceID); =============写入命名空间id
out.writeLong(fsDir.rootDir.numItemsInTree()); =============写入根目录(这里指的是dfs.name.dir)
out.writeLong(fsNamesys.getGenerationStamp()); =============写入创建文件系统时间戳
byte[] byteStore = new byte[4*FSConstants.MAX_PATH_LENGTH];
ByteBuffer strbuf = ByteBuffer.wrap(byteStore);
// save the root
saveINode2Image(strbuf, fsDir.rootDir, out); =============写入文件或者目录的元数据信息,包括复制级别,修改时间,访问时间,块信息等
// save the rest of the nodes
saveImage(strbuf, 0, fsDir.rootDir, out);
fsNamesys.saveFilesUnderConstruction(out);
fsNamesys.saveSecretManagerState(out);
strbuf = null;
} finally {
out.close();
}
LOG.info("Image file of size " + newFile.length() + " saved in "
+ (FSNamesystem.now() - startTime)/1000 + " seconds.");
}
=========================================================
可以看到,采用了递归调用的方式(saveINode2Image,saveImage)将root目录树结构存储了起来。
最后来看下saveINode2Image这个方法:
private static void saveINode2Image(ByteBuffer name,
INode node,
DataOutputStream out) throws IOException {
int nameLen = name.position();
out.writeShort(nameLen);
out.write(name.array(), name.arrayOffset(), nameLen);
if (!node.isDirectory()) { // write file inode
INodeFile fileINode = (INodeFile)node;
out.writeShort(fileINode.getReplication());
out.writeLong(fileINode.getModificationTime());
out.writeLong(fileINode.getAccessTime());
out.writeLong(fileINode.getPreferredBlockSize());
Block[] blocks = fileINode.getBlocks();
out.writeInt(blocks.length);
for (Block blk : blocks)
blk.write(out);
FILE_PERM.fromShort(fileINode.getFsPermissionShort());
PermissionStatus.write(out, fileINode.getUserName(),
fileINode.getGroupName(),
FILE_PERM);
} else { // write directory inode
out.writeShort(0); // replication
out.writeLong(node.getModificationTime());
out.writeLong(0); // access time
out.writeLong(0); // preferred block size
out.writeInt(-1); // # of blocks
out.writeLong(node.getNsQuota());
out.writeLong(node.getDsQuota());
FILE_PERM.fromShort(node.getFsPermissionShort());
PermissionStatus.write(out, node.getUserName(),
node.getGroupName(),
FILE_PERM);
}
}
这个方法很明显,分为文件和目录两个部分,如果使文件的话,记录的信息包括文件的块大小,一个文件包括哪些块(块id,块的数量等),如果是目录,大多属性都设置为0
相关文章推荐
- HDFS-2.7.0系列2: hadoop namenode -format脚本解析
- hadoop 2.5 hdfs namenode –format 出错Usage: java NameNode [-backup] |
- 解决hadoop namenode -format / hdfs namenode -format 找不到java的文件目录
- hdfs格式化hadoop namenode -format错误
- Hadoop学习笔记14:./bin/hadoop namenode -format之源码解析
- Hadoop源码分析之NameNode--Format
- Hadoop-2.4.1学习之NameNode -format源码分析
- 多次进行hdfs namenode -format命令时,启动DataNode自动死亡的原因
- 大数据 (三)Hadoop-HDFS namenode的HA --- zookeeper的引出
- [root@master java]# hadoop namenode -format DEPRECATED: Use of this script to execute hdfs command i
- 为什么每次重启机器后,namenode都启动不了,需要先hadoop namenode -format
- 【数据平台】关于Hadoop集群namenode format安全事故
- hadoop namenode format做了什么?
- Hadoop HDFS Namenode启动不成功
- hadoop执行hdfs namenode -bootstrapStandby报错FATAL ha.BootstrapStandby的解决方法
- Hadoop之HDFS及NameNode单点故障解决方案
- hadoop namenode –format 错误
- Hadoop的HDFS中namenode和datenode内容分析
- 关于Hadoop伪分布式每次启动都要format namenode
- "hadoop namenode -format"命令的作用和影响的文件