HDFS源码分析之FSImage文件内容(一)总体格式
FSImage文件是HDFS中名字节点NameNode上文件/目录元数据在特定某一时刻的持久化存储文件。它的作用不言而喻,在HA出现之前,NameNode因为各种原因宕机后,若要恢复或在其他机器上重启NameNode,重新组织元数据,就需要加载对应的FSImage文件、FSEditLog文件,并在内存中重做FSEditLog文件中的事务条目。本节,我们先来看下FSImage文件格式,及其内部数据是如何组织的。
通过翻看HDFS中加载FSImage文件的代码,从FSNamesystem的loadFSImage()方法开始,我将HDFS集群上的一个FSImage文件放到本地Windows系统中的F盘下,并写了如下方法解析文件,并打印关键内容,如下:
- import java.io.IOException;
- import java.io.File;
- import java.util.List;
- import org.junit.Test;
- import java.io.ByteArrayInputStream;
- import java.io.RandomAccessFile;
- import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary;
- import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary.Section;
- public class TestImageUtil {
- @Test
- public void testImage() {
- // 文件头字符串HDFSIMG1对应byte[]
- byte[] fileHead = "HDFSIMG1".getBytes();
- RandomAccessFile raFile = null;
- try {
- // 创建文件file,对应为f盘下FSImage文件fsimage_0000000000002311798
- File file = new File("f:/fsimage_0000000000002311798");
- raFile = new RandomAccessFile(file, "r");
- // 文件summary长度域所占大小为4
- final int FILE_LENGTH_FIELD_SIZE = 4;
- System.out.println("文件summary长度域大小:FILE_LENGTH_FIELD_SIZE=" + FILE_LENGTH_FIELD_SIZE);
- // 获取FSImage文件长度
- long fileLength = raFile.length();
- System.out.println("获取FSImage文件长度:fileLength=" + fileLength);
- // 创建文件头byte[]数组fileHeadTmp,用于存储文件头byte[]数组,大小为上述fileHead数组大小
- byte[] fileHeadTmp = new byte[fileHead.length];
- // 读入文件头至byte[]数组fileHeadTmp
- System.out.println("文件从头开始读取" + fileHeadTmp.length + "个byte至byte[]数组fileHeadTmp");
- raFile.readFully(fileHeadTmp);
- // 获取文件头长度
- System.out.println("获取文件头长度:fileHeadLength=" + fileHead.length);
- // 将byte[]数组fileHeadTmp转换成字符串fileHeadString
- String fileHeadString = new String(fileHeadTmp);
- // 验证文件头字符串
- System.out.println("fileHeadString=" + fileHeadString);
- // 文件file通过raFile.seek()方法定位到文件summary长度字段起始处,即文件大小减去文件summary长度域所占字节数4
- raFile.seek(fileLength - FILE_LENGTH_FIELD_SIZE);
- System.out.println("文件定位到文件summary长度开始处:" + (fileLength - FILE_LENGTH_FIELD_SIZE));
- // 读入一个int,即文件长度summaryLength
- int summaryLength = raFile.readInt();
- System.out.println("获取文件summary部分长度:summaryLength=" + summaryLength);
- // 文件file通过raFile.seek()方法定位到文件summary部分开始处,即文件大小减去文件长度所占字节数4,再减去文件内容总长度
- raFile.seek(fileLength - FILE_LENGTH_FIELD_SIZE - summaryLength);
- System.out.println("文件定位到文件summary部分开始处:" + (fileLength - FILE_LENGTH_FIELD_SIZE - summaryLength));
- // 再从当前位置开始读入文件summary部分内容
- // 构造文件长度summaryLength大小的byte[]数组
- byte[] summaryBytes = new byte[summaryLength];
- // 读取文件内容至数组summaryBytes
- raFile.readFully(summaryBytes);
- System.out.println("从当前位置开始读入文件summary部分内容至summaryBytes数组");
- FileSummary summary = FileSummary
- .parseDelimitedFrom(new ByteArrayInputStream(summaryBytes));
- System.out.println("解析文件summary部分内容如下:");
- System.out.println("1、ondiskVersion=" + summary.getOndiskVersion());
- System.out.println("2、layoutVersion=" + summary.getLayoutVersion());
- System.out.println("3、codec=" + summary.getCodec());
- System.out.println("4、section");
- List<Section> sectionsList = summary.getSectionsList();
- for (Section section : sectionsList) {
- System.out.println(" ");
- System.out.println("name=" + section.getName());
- System.out.println("length=" + section.getLength());
- System.out.println("offset=" + section.getOffset());
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (raFile != null) {
- try {
- raFile.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * Supported section name. The order of the enum determines the order of
- * loading.
- */
- public enum SectionName {
- NS_INFO("NS_INFO"), STRING_TABLE("STRING_TABLE"), EXTENDED_ACL(
- "EXTENDED_ACL"), INODE("INODE"), INODE_REFERENCE(
- "INODE_REFERENCE"), SNAPSHOT("SNAPSHOT"), INODE_DIR("INODE_DIR"), FILES_UNDERCONSTRUCTION(
- "FILES_UNDERCONSTRUCTION"), SNAPSHOT_DIFF("SNAPSHOT_DIFF"), SECRET_MANAGER(
- "SECRET_MANAGER"), CACHE_MANAGER("CACHE_MANAGER");
- private static final SectionName[] values = SectionName.values();
- public static SectionName fromString(String name) {
- for (SectionName n : values) {
- if (n.name.equals(name))
- return n;
- }
- return null;
- }
- private final String name;
- private SectionName(String name) {
- this.name = name;
- }
- }
- }
关于代码解释,我们会在专门的FSImage文件加载源码分析相关文章中进行详细介绍,本文只关注FSImage文件的总体格式。
执行上述方法,打印内容输出如下:
- 文件summary长度域大小:FILE_LENGTH_FIELD_SIZE=4
- 获取FSImage文件长度:fileLength=1154156
- 文件从头开始读取8个byte至byte[]数组fileHeadTmp
- 获取文件头长度:fileHeadLength=8
- fileHeadString=HDFSIMG1
- 文件定位到文件summary长度开始处:1154152
- 获取文件summary部分长度:summaryLength=231
- 文件定位到文件summary部分开始处:1153921
- 从当前位置开始读入文件summary部分内容至summaryBytes数组
- 解析文件summary部分内容如下:
- 1、ondiskVersion=1
- 2、layoutVersion=-60
- 3、codec=
- 4、section
- name=NS_INFO
- length=27
- offset=8
- name=INODE
- length=1093067
- offset=35
- name=INODE_DIR
- length=60225
- offset=1093102
- name=FILES_UNDERCONSTRUCTION
- length=345
- offset=1153327
- name=SNAPSHOT
- length=68
- offset=1153672
- name=SNAPSHOT_DIFF
- length=36
- offset=1153740
- name=INODE_REFERENCE
- length=0
- offset=1153776
- name=SECRET_MANAGER
- length=9
- offset=1153776
- name=CACHE_MANAGER
- length=7
- offset=1153785
- name=STRING_TABLE
- length=129
- offset=1153792
不难看出,文件的总长度为1154156,这与我通过windows系统下右击-属性的方式查看结果是一致的,如下:
(一)文件的起始位置(下标我们从0开始),0-7处为文件头信息,占8个byte的"HDFSIMG1";
(二)然后是接下来是10个section区域,这部分在FSImage文件中所占起止位置为8-1153920,这些是根据下面的summary区域的分析得到的结论,section分别如下:
1、8-34:占27个byte的section--NS_INFO,命名系统NameSystem信息section区域,具体内容后续文章再讲;
2、35-1093101:占1093067个byte的section--INODE,HDFS中INODE节点section区域,具体内容后续文章再讲;
3、1093102-1153326:占60225个byte的section--INODE_DIR,HDFS中INODE目录节点section区域,具体内容后续文章再讲;
4、1153327-1153671:占345个byte的section--FILES_UNDERCONSTRUCTION,HDFS中FILES_UNDERCONSTRUCTION处于构建状态文件部分section区域,具体内容后续文章再讲;
5、1153672-1153739:占68个byte的section--SNAPSHOT,HDFS中SNAPSHOT快照部分section区域,具体内容后续文章再讲;
6、1153740-1153775:占36个byte的section--SNAPSHOT_DIFF,HDFS中SNAPSHOT_DIFF部分section区域,具体内容后续文章再讲;
7、1153776-?:占0个byte的section--INODE_REFERENCE,HDFS中INODE_REFERENCE节点引用部分section区域,具体内容后续文章再讲,实际上本文件中没有这部分,为了体现FSImage文件的完整性,还是增加这部分的描述;
8、1153776-1153784:占9个byte的section--SECRET_MANAGER,HDFS中SECRET_MANAGER部分section区域,具体内容后续文章再讲;
9、1153785-1153791:占7个byte的section--CACHE_MANAGER,HDFS中CACHE_MANAGER部分section区域,具体内容后续文章再讲;
10、1153792-1153920:占129个byte的section--STRING_TABLE,HDFS中STRING_TABLE部分section区域,具体内容后续文章再讲;
(三)再接下来是文件summary区域,这部分在FSImage文件中所占起止位置为1153921-1154151,长度为231,它主要标识了上述各section区域的区域名name、在FSImage文件所占长度length及其起始位置offset,另外还有三个十分总要的变量,FSImage文件在磁盘上的版本号ondiskVersion、布局layout版本号layoutVersion及其解压/压缩器codec,前面两个会在load文件时与HDFS中NameNode进程内存中的版本号分别进行校验,防止错误版本的FSImage文件被加载,而codec则用于如何加载各个section区域,为空默认不做任何解压/压缩处理;
(四)最后为文件summary部分所占长度区域,这部分在FSImage文件中所占起止位置为1154152-1154155,正好是文件的最后一部分内容。
或许通过图的方式你会看的更直观,但是请原谅我拙劣的画图技巧:
实际上,FSImage文件中各个区域包含的内容,采用的是Google的protobuf编码格式,而protobuf不单单是一种消息传输格式,你也可以把它理解为一种数据编码格式,所以各个区域数据格式,在HDFS内的fsimage.proto文件中也有所阐述,比如FileSummary:
- message FileSummary {
- // The version of the above EBNF grammars.
- required uint32 ondiskVersion = 1;
- // layoutVersion describes which features are available in the
- // FSImage.
- required uint32 layoutVersion = 2;
- optional string codec = 3;
- // index for each section
- message Section {
- optional string name = 1;
- optional uint64 length = 2;
- optional uint64 offset = 3;
- }
- repeated Section sections = 4;
- }
它就包含我们上面所描述的ondiskVersion、layoutVersion、codec、sections五部分,最后的sections是可以重复的,即repeated,而每个section又是一个message,包含name、length、offset三部分,正和我们上面解析的结果一致。
又如StringTableSection:
- /**
- * This section maps string to id
- * NAME: STRING_TABLE
- */
- message StringTableSection {
- message Entry {
- optional uint32 id = 1;
- optional string str = 2;
- }
- optional uint32 numEntry = 1;
- // repeated Entry
- }
包含两部分,Entry数量:numEntry,和重复的Entry,每个Entry又是一个Message,包含id和str两部分。
以上就是FSImage文件的主体信息,至于文件中的详细内容,特别是每个不同section区域中都有哪些内容,尤其是复杂的INodeSection等,我们后续再讲!
HDFS源码分析之FSImage文件内容(一)总体格式的更多相关文章
- HDFS源码分析数据块校验之DataBlockScanner
DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...
- HDFS源码分析EditLog之读取操作符
在<HDFS源码分析EditLog之获取编辑日志输入流>一文中,我们详细了解了如何获取编辑日志输入流EditLogInputStream.在我们得到编辑日志输入流后,是不是就该从输入流中获 ...
- HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState
关于数据块.副本的介绍,请参考文章<HDFS源码分析之数据块Block.副本Replica>. 一.数据块状态BlockUCState 数据块状态用枚举类BlockUCState来表示,代 ...
- HDFS源码分析EditLog之获取编辑日志输入流
在<HDFS源码分析之EditLogTailer>一文中,我们详细了解了编辑日志跟踪器EditLogTailer的实现,介绍了其内部编辑日志追踪线程EditLogTailerThread的 ...
- HDFS源码分析心跳汇报之数据块汇报
在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...
- Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作
在Yii中,当请求一个Url的时候,首先在application中获取request信息,然后由request通过urlManager解析出route,再在Module中根据route来创建contr ...
- HDFS源码分析之UnderReplicatedBlocks(一)
http://blog.csdn.net/lipeng_bigdata/article/details/51160359 UnderReplicatedBlocks是HDFS中关于块复制的一个重要数据 ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
- HDFS源码分析数据块复制监控线程ReplicationMonitor(一)
ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...
随机推荐
- 集群/分布式/微服务/SOA 转
https://www.cnblogs.com/Java3y/p/9479410.html 二.集群/分布式/微服务/SOA是什么? 像我这种技术小白,看到这些词(集群/分布式/微服务/SOA)的时候 ...
- TCP/IP,http,socket,长连接,短连接 —— 小结
TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. 在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议. 在传输层中有TCP协议 ...
- 十. 图形界面(GUI)设计3.标签、按钮和按钮事件
标签和按钮也许是图形界面中最常见的两种组件,按钮又总是与激发动作事件有关. 标签 标签(JLabel)是最简单的Swing组件.标签对象的作用是对位于其后的界面组件作说明.可以设置标签的属性,即前景色 ...
- Bluetooth篇 开发实例之十一 官网的Bluetooth Chat sample的bug
当没有匹配的设备和没有找到可用设备的时候. // If there are paired devices, add each one to the ArrayAdapter if (pairedDev ...
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 如果你正在为你的业务模型使用 ...
- Delphi CRC算法, 不错
http://www.cnblogs.com/tangqs/archive/2011/12/08/2280255.html
- 在Android中解决内存溢出 – OutOfMemoryError
原文链接:http://riggaroo.co.za/fixing-memory-leaks-in-android-outofmemoryerror/ 注:本文在原文基础上在如何判断内存是否泄露方面进 ...
- java、freemarker保留两位小数
一.Java保留2位小数 double acc = 22.4322; String accX = String.format("%.2f", acc); 二.freemarker保 ...
- Microsoft Sync Framework 2.1 可再发行程序包 Microsoft Sync Framework 1.0 SP1 - 中文(简体)
Sync Framework 2.1 引入了新功能,这些功能支持您计算机上的 SQL Server 或 SQL Server Compact 数据库与 SQL Azure 数据库进行同步.此发行版还引 ...
- OpenCV2学习笔记(十五):利用Cmake高速查找OpenCV函数源代码
在使用OpenCV时,在对一个函数的调用不是非常了解的情况下,通常希望查到该函数的官方声明.而假设想进一步研究OpenCV的函数,则必须深入到源码. 在VS中我们能够选中想要查看的OpenCV函数,点 ...