原文地址:http://www.pluscn.net/?p=833
本文主要描述HDFS中的NameNode、DataNode、Secondary NameNode 是如何在磁盘上组织、存储持久化数据的。
1. NameNode 结构
在HDFS中,namenode提供整个HDFS文件系统的namespace管理,块管理以及与metadata相关的服务。
最新格式化的NameNode会创建以下目录结构:
${dfs.name.dir}/current/{VERSION,edits,fsimage,fstime}
其中,dfs.name.dir是一个目录列表,存储每个目录的镜像。VERSION文件是Java属性文件,包含运行HDFS的版本信息。
edits,是编辑日志文件。当客户断执行写操作的时,NameNode首先会在编辑日志中写下记录,并在内存中保存一个文件系统元数据,这个描述符会在编辑日志有了改动后更新。内存中的元数据用来提供读数据请求服务。
编辑日志会在每次成功操作之后,且成功代码尚未返回给客户端之前进行刷新和同步。对于要写入多个目录的操作,该写入流要刷新和同步到所有的副本上,这就保证了操作不会因故障丢失数据。
fsimage 是一个二进制文件,当中记录了HDFS中所有文件和目录的元数据信息。
该文件中保存的以序列化格式存储的文件inodes和文件目录的格式如下:
其中,每个inodes 表征一个文件或目录的元数据信息,以及文件的副本数、访问和修改时间等信息。
在namenode启动时,就需要对fsimage按照上面的格式进行顺序的加载,以将fsimage中记录的HDFS元数据信息加载到内存中。
和编辑日志不同的是,它不会在每个文件系统的写操作后进行更新,因为写出fsimage文件会非常慢(fsimage可能增长到GB大小)。
fstime,是上一次新打开一个操作日志的时间(long型)。
NameNode启动过程
fsimage加载过程
Fsimage加载过程完成的操作主要是为了:
1. 从fsimage中读取该HDFS中保存的每一个目录和每一个文件
2. 初始化每个目录和文件的元数据信息
3. 根据目录和文件的路径,构造出整个namespace在内存中的镜像
4. 如果是文件,则读取出该文件包含的所有blockid,并插入到BlocksMap中。
整个加载流程如下图所示:
如上图所示,namenode在加载fsimage过程其实非常简单,就是从fsimage中不停的顺序读取文件和目录的元数据信息,并在内存中构建整个namespace,同时将每个文件对应的blockid保存入BlocksMap中,此时BlocksMap中每个block对应的datanodes列表暂时为空。当fsimage加载完毕后,整个HDFS的目录结构在内存中就已经初始化完毕。
2.DataNode结构
DataNode是文件系统中真正存储数据的地方,其周期性的向元数据节点回报期存储的数据块信息。
datanode的存储目录由dfs.data.dir属性设置,该目录是datanode启动时自动创建的,不需要进行格式化,目录的结构如下所示:
${dfs.data.dir}/current/VERSION /blk_<id_1> /blk_<id_1>.meta /blk_<id_1> /blk_<id_1>.meta /... /blk_<id_64> /blk_<id_64>.meta /subdir0/ /subdir1/ /... /subdir63/ /previous/ /detach/ /tmp/ /in_use.lock /storage
current是当前的工作目录,previous是升级HDFS之前的工作目录,在升级时,HDFS并不会将文件从previous拷贝到current目录中,而是遍历previous中的所有文件,在current目录中创建硬链接。
detach目录保存用于copy-on-write的文件,在Datanode重启时需要恢复。
tmp目录保存一些临时数据。
in_use.lock文件用于对datanode加锁,storage文件保存了布局版本及升级版本提示信息。
下面来看current目录的结构,目录中的文件都有blk_前缀,有两类文件:块文件和块元数据文件(.meta后缀)。当目录中数据块的数量增加到64个(由dfs.datanode.numblocks属性设置,子目录的数量也是由该属性设置),datanode会创建一个子目录来存放新的数据。采用树状结构的组织方式,datanode可以有效管理各个目录中的文件,避免将很多文件放在一个目录之中。
3. Secondary NameNode
Secondary NameNode(从元数据节点或者辅助节点)是一个辅助NameNode 处理fsimage和编辑日志的节点,它从NameNode中拷贝fsimage和编辑日志到临时目录,并定期的合并成一个新的fsimage,随后会将新的fsimage上传到NameNode。
辅助Namenode的存储目录由fs.checkpoint.dir属性设置,目录的结构如下所示:
$(fs.checkpoint.dir}/current/VERSION /edits /fsimage /fstime /previous.checkpoint/VERSION /edits /fsimage /fstime
Secondary NameNode并不是NameNode的备用节点,它与NameNode有着不同的职责(二者的服务可以运行在一台机器上),其主要功能是周期性的将元数据节点的命名空间镜像文件和修改日志合并,以防止日志文件过大,合并后的命名空间镜像文件在从元数据节点中叶保存一份,以防元数据节点失效的时候用于恢复。
元数据节点使用日志记录元数据的修改,其工作主要包括:
当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit log)
元数据节点在内存中保存了文件系统的元数据信息,在记录了修改日志后,元数据节点则修改内存中的数据结构。
每次的写操作成功之前,修改日志都会同步(sync)到文件系统。
命名空间映像文件(fsimage)是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在硬盘上直接修改。
当元数据节点失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,然后逐一重新执行修改日志中的操作。
从元数据节点用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上,checkpoint的过程如下图所示:
- 从元数据节点通知元数据节点生成新的日志文件,以后的日志都写到新的日志文件中。
- 从元数据节点用http get从元数据节点获得fsimage文件及旧的日志文件。
- 从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。
- 从元数据节点奖新的fsimage文件用http post传回元数据节点
- 元数据节点可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件,然后更新fstime文件,写入此次checkpoint的时间。
- 这样元数据节点中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变的很大了,从而使得元数据节点启动时花费很少的时间进行日志的合并。
参考