hadoop namenode启动过程

NameNode启动过程详细剖析

1. FSImage
Namenode会将HDFS的文件和目录元数据存储在一个叫fsimage的二进制文件中,每次保存fsimage之后到下次保存之间的所有hdfs操作,将会记录在editlog文件中,当editlog达到一定的大小(bytes,由fs.checkpoint.size参数定义)或从上次保存过后一定时间段过后(sec,由fs.checkpoint.period参数定义),namenode会重新将内存中对整个HDFS的目录树和文件元数据刷到fsimage文件中。Namenode就是通过这种方式来保证HDFS中元数据信息的安全性。
Fsimage是一个二进制文件,当中记录了HDFS中所有文件和目录的元数据信息在我的Hadoop的HDFS版中,该文件的中保存文件和目录的格式如下:

在第一次启动的时候,我们需要格式化文件系统 ,那么为什么需要格式化文件系统呢,就是为了创建这个FSImage 文件,

在这里插入图片描述
当namenode重启加载fsimage时,就是按照如下格式协议从文件流中加载元数据信息。从fsimag的存储格式可以看出,fsimage保存有如下信息:

  • 首先是一个image head,其中包含:**

a) imgVersion(int):当前image的版本信息

b) namespaceID(int):用来确保别的HDFS instance中的datanode不会误连上当前NN。

c) numFiles(long):整个文件系统中包含有多少文件和目录

d) genStamp(long):生成该image时的时间戳信息。

- 接下来便是对每个文件或目录的源数据信息,如果是目录,则包含以下信息:

a) path(String):该目录的路径,如”/user/build/build-index”

b) replications(short):副本数(目录虽然没有副本,但这里记录的目录副本数也为3)

c) mtime(long):该目录的修改时间的时间戳信息

d) atime(long):该目录的访问时间的时间戳信息

e) blocksize(long):目录的blocksize都为0

f) numBlocks(int):实际有多少个文件块,目录的该值都为-1,表示该item为目录

g) nsQuota(long):namespace Quota值,若没加Quota限制则为-1

h) dsQuota(long):disk Quota值,若没加限制则也为-1

i) username(String):该目录的所属用户名

j) group(String):该目录的所属组

k) permission(short):该目录的permission信息,如644等,有一个short来记录。

- 若从fsimage中读到的item是一个文件,则还会额外包含如下信息:

a) blockid(long):属于该文件的block的blockid,

b) numBytes(long):该block的大小

c) genStamp(long):该block的时间戳

当该文件对应的numBlocks数不为1,而是大于1时,表示该文件对应有多个block信息,此时紧接在该fsimage之后的就会有多个blockid,numBytes和genStamp信息。

因此,在namenode启动时,就需要对fsimage按照如下格式进行顺序的加载,以将fsimage中记录的HDFS元数据信息加载到内存中。

2. BlockMap
从以上fsimage中加载如namenode内存中的信息中可以很明显的看出,在fsimage中,并没有记录每一个block对应到哪几个datanodes的对应表信息,而只是存储了所有的关于namespace的相关信息。而真正每个block对应到datanodes列表的信息在hadoop中并没有进行持久化存储,而是在所有datanode启动时,每个datanode对本地磁盘进行扫描,将本datanode上保存的block信息汇报给namenode,namenode在接收到每个datanode的块信息汇报后,将接收到的块信息,以及其所在的datanode信息等保存在内存中。HDFS就是通过这种块信息汇报的方式来完成 block -> datanodes list的对应表构建。Datanode向namenode汇报块信息的过程叫做blockReport,而namenode将block -> datanodes list的对应表信息保存在一个叫BlocksMap的数据结构中。

BlocksMap的内部数据结构如下:

在这里插入图片描述
如上图显示,BlocksMap实际上就是一个Block对象对BlockInfo对象的一个Map表,其中Block对象中只记录了blockid,block大小以及时间戳信息,这些信息在fsimage中都有记录。而BlockInfo是从Block对象继承而来,因此除了Block对象中保存的信息外,还包括代表该block所属的HDFS文件的INodeFile对象引用以及该block所属datanodes列表的信息(即上图中的DN1,DN2,DN3,该数据结构会在下文详述)。

因此在namenode启动并加载fsimage完成之后,实际上BlocksMap中的key,也就是Block对象都已经加载到BlocksMap中,每个key对应的value(BlockInfo)中,除了表示其所属的datanodes列表的数组为空外,其他信息也都已经成功加载。所以可以说:fsimage加载完毕后,BlocksMap中仅缺少每个块对应到其所属的datanodes list的对应关系信息。所缺这些信息,就是通过上文提到的从各datanode接收blockReport来构建。当所有的datanode汇报给namenode的blockReport处理完毕后,BlocksMap整个结构也就构建完成。

BlockMap中datanode列表数据结构
在BlockInfo中,将该block所属的datanodes列表保存在一个Object[]数组中,但该数组不仅仅保存了datanodes列表,还包含了额外的信息。实际上该数组保存了如下信息:
在这里插入图片描述
上图表示一个block包含有三个副本,分别放置在DN1,DN2和DN3三个datanode上,每个datanode对应一个三元组,该三元组中的第二个元素,即上图中prev block所指的是该block在该datanode上的前一个BlockInfo引用。第三个元素,也就是上图中next Block所指的是该block在该datanode上的下一个BlockInfo引用。每个block有多少个副本,其对应的BlockInfo对象中就会有多少个这种三元组。
Namenode采用这种结构来保存block->datanode list的目的在于节约namenode内存。由于namenode将block->datanodes的对应关系保存在了内存当中,随着HDFS中文件数的增加,block数也会相应的增加,namenode为了保存block->datanodes的信息已经耗费了相当多的内存,如果还像这种方式一样的保存datanode->block list的对应表,势必耗费更多的内存,而且在实际应用中,要查一个datanode上保存的block list的应用实际上非常的少,大部分情况下是要根据block来查datanode列表,所以namenode中通过上图的方式来保存block->datanode list的对应关系,当需要查询datanode->block list的对应关系时,只需要沿着该数据结构中next Block的指向关系,就能得出结果,而又无需保存datanode->block list在内存中。
NameNode启动过程
fsimage加载过程
Fsimage加载过程完成的操作主要是为了:

  • 从fsimage中读取该HDFS中保存的每一个目录和每一个文件
  • 初始化每个目录和文件的元数据信息
  • 根据目录和文件的路径,构造出整个namespace在内存中的镜像
  • 如果是文件,则读取出该文件包含的所有blockid,并插入到BlocksMap中。 整个加载流程如下图所示:
    在这里插入图片描述

如上图所示,namenode在加载fsimage过程其实非常简单,就是从fsimage中不停的顺序读取文件和目录的元数据信息,并在内存中构建整个namespace,同时将每个文件对应的blockid保存入BlocksMap中,此时BlocksMap中每个block对应的datanodes列表暂时为空。当fsimage加载完毕后,整个HDFS的目录结构在内存中就已经初始化完毕,所缺的就是每个文件对应的block对应的datanode列表信息。这些信息需要从datanode的blockReport中获取,所以加载fsimage完毕后,namenode进程进入rpc等待状态,等待所有的datanodes发送blockReports。

blockReport阶段
每个datanode在启动时都会扫描其机器上对应保存hdfs block的目录下(dfs.data.dir)所保存的所有文件块,然后通过namenode的rpc调用将这些block信息以一个long数组的方式发送给namenode,namenode在接收到一个datanode的blockReport rpc调用后,从rpc中解析出block数组,并将这些接收到的blocks插入到BlocksMap表中,由于此时BlocksMap缺少的仅仅是每个block对应的datanode信息,而namenoe能从report中获知当前report上来的是哪个datanode的块信息,所以,blockReport过程实际上就是namenode在接收到块信息汇报后,填充BlocksMap中每个block对应的datanodes列表的三元组信息的过程。其流程如下图所示:
在这里插入图片描述
当所有的datanode汇报完block,namenode针对每个datanode的汇报进行过处理后,namenode的启动过程到此结束。此时BlocksMap中block->datanodes的对应关系已经初始化完毕。如果此时已经达到安全模式的推出阈值,则hdfs主动退出安全模式,开始提供服务。
转载自https://blog.csdn.net/lzlchangqi/article/details/14146407

欢迎关注,更多惊喜等着你

这里写图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值