唯有前进值得敬仰

---等得越久,相聚时越幸福
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

hdfs源码namenode部分概述(一)

Posted on 2011-09-01 21:50  绿豆芽33  阅读(6740)  评论(2编辑  收藏  举报

  关于hdfs源码的阅读,我这个小菜鸟觉得有这么两种方式去读,一是抓住它关键的数据结构,知道了他们是干什么用的,剩下的就是一些围着他们转的操作了;二是跟踪执行过程的流程式阅读,以mkdir为例,从client应用发出mkdir请求到传递给namenode,再在datanode上执行,这么一个过程详细地跟踪下来,就理解了一大片。两种路子没有孰优孰劣,配合使用或许更有效。本篇先从数据结构的角度分享一点自己读namenode部分源码的收获。

  这是一张任何介绍hdfs的文章都会出现的架构图。采用的是master/slave模型,一个hdfs cluster包含一个NameNode和若干的DataNode,NameNode(以下简称nn)是master,主要负责管理hdfs文件系统,具体地包括namespace管理(其实就是目录结构),block管理(其中包括 filename->block,block->ddatanode list的对应关系)。nn提供的是始终被动接收服务的server,主要有三类协议接口:ClientProtocol接口、DatanodeProtocol接口、NamenodeProtocol接口,貌似还有一种,忘记了。DataNode(简称dn)主要是用来存储数据文件,hdfs将一个文件分割成一个个的block,这些block可能存储在一个DataNode上或者是多个DataNode上。dn负责实际的底层的文件的读写,如果客户端client程序发起了读hdfs上的文件的命令,那么首先将这些文件分成block,然后nn将告知client这些block数据是存储在那些dn上的,之后,client将直接和dn交互。

  体系结构中还有个节点没画出来,Secondary NameNode,该部分主要是定时对NameNode进行数据snapshots进行备份,这样尽量降低NameNode崩溃之后,导致数据的丢失,其实所作的工作就是从nn获得fsimage和edits把二者重新合并然后发给nn,这样,既能减轻nn的负担又能保险地备份。

  好了,下面开始正题。

不管是client还是dn的消息发到nn后最终都会落到FSnamesystem身上,这是一个重量级家伙,如图,对各种服务请求的处理都转交给它完成,它提供了对各种数据结构操作的接口,这些数据结构共同维护了整个namenode的元数据信息。

nn的主要数据结构有:

一个一个介绍。

FSdirectory:

FSDirectory存储整个文件系统的目录状态,对整个目录结构的管理通过调用FSImage和FSEditLog的方法从namenode本地磁盘读取元数据信息和向本地磁盘写入元数据信息,并登记对目录结构所作的修改到日志文件。另外,FSDirectory保存了文件名和数据块的映射关系。

INode是对文件系统目录结构中一个节点的抽象

INodeFile和INodeDirectory均继承自INode类,分别表示文件节点和目录节点。

INodeFile类中最重要的数据结构是BlockInfo blocks[],它记录了一个文件所包含的所有Block,成员方法的操作大都与Block相关

INodefileUnderConstruction表示正在都建的文件

INodeDirectory的关键数据结构是List<INode> children记录了目录下所有的子节点信息

INodeDirectoryWithQuota表示有配额限制的目录,根目录就是这种类型。

FSimage:

把文件和目录的元数据信息持久化地存储到fsimage文件中,每次启动时从中将元数据加载到内存中构建目录结构树,之后的操作记录在edits log中

定期将edits与fsimage合并刷到fsimage中

loadFSImage(File curFile)用于从fsimage中读入Namenode持久化的信息。fsimage中保存的元数据信息格式如下,hdfs加载和写入时都按照该格式进行

fsimage是一个二进制文件,当中记录了HDFS中所有文件和目录的元数据信息,格式如下,这是网上流传的一张经典图,这是淘宝的一个师兄画的,拿来站沾光。

imageVersion(int)——image版本号

namespaceID(int)——命名空间ID,在namenode的生命期内保持不变,datanode注册时

返回作为其registrationID,每次和namenode通信时都要检查,不认识的namespaceID拒绝连接.

numFiles(16版以后long型)记录文件系统中的文件数

genstamp(long)生成image时间戳

下面是numFiles个文件(目录)信息:

path(String)文件或目录路径

replication(int)副本数,会调用FSEditLog.adjustReplication(replication);调整,目录的为0

mtime(long)修改时间

atime(long)访问时间

blockSize(long)块大小,目录是0

NumBlocks(int)文件包含的块数(imageVersion 9以后的版本numBlocks>=0时表示文件,之前的版本>0时表示文件),目录的为-1,saveINode2Image方法中可以看到

如果是文件,下面是NumBlocks个block的相关信息:

blockId(long):该文件的block的blockid,

numBytes(long):该block的大小

generationStamp(long):该block的时间戳

如果是目录,读入quota信息:

nsQuota(long)命名空间大小配额,默认-1

dsQuota(long)磁盘空间配额,默认-1

下面是权限相关

username(String)文件或目录的所属用户名

groupname(String)组名

permission(short)权限

如果前面的path.length==0,表示根目录,设置根目录的配额,修改时间,访问时间和权限信息。

将这些信息读入内存之后,构造一个文件目录结构树,将表示文件或目录的节点填入到结构中。

然后是加载datanode信息(新版已取消该项)

再之后是加载FilesUnderConstruction.

BlocksMap:

block->datanode的信息没有持久化存储,而是namenode通过datanode的blockreport获取block->datanode list

BlocksMap负责维护了三种信息:

  block->datanode list

  block->INodeFile

  datanode->blocks

这要归功于一个很牛逼的结构:Object[] triplets

他是一个三元组,每个block有几个副本,就有几个三元组。三元组的第一个元素表示该block所属的Datanode,类型是DatanodeDescriptor,通过它获得

block->datanode list

第二/三个元素表示该block所在Datanode上的前/后一个block(前驱和后继),类型是BlockInfo,通过它获得datanode->blocks

借助这个三元组可以找到一个block所属的所有datanode,也可以通过三元组的后两个元素信息找到一个datanode上所有的block。

上面这两个结构介绍之后,nn需要的namespace信息和block信息基本就全了。在nn加载fsimage完成之后,BlocksMap中只有每个block到其所属的datanodes list的对应关系信息还没建立。然后通过dn的blockReport来收集构建。当所有的dn汇报给nn的blockReport处理完毕后,BlocksMap整个结构也就构建完成了。

今天先写到这。。。