您的位置:  首页 > 技术杂谈 > 正文

hdfs——nn的启动优化

2022-01-26 14:00 https://my.oschina.net/hncscwc/blog/5415309 hncscwc 次阅读 条评论


【概述】


上一篇文章讲解了,在一定DN节点规模,一定block数据量下的并发写文件的优化问题。

在这种节点、数据量规模的集群中,当HDFS全部重启(nn+dn全部重启),或者两个NN都重启后,需要经过较长时间,才能真正对外提供服务。


那么nn启动过程中都干了些啥,主要耗时点在哪,以及应当如何优化,本文就来聊聊这些问题——启动优化。


【启动流程与耗时分析】


NN的启动可以粗略的分为以下几个步骤:

  • 启动http服务

  • 加载文件系统

  • 启动rpc服务

  • 按需启动插件服务

  • 处理dn的注册以及dn的全量块汇报


其中启动HTTP服务、RPC服务,都是在对应配置的IP端口上进行监听,然后创建对应的reader线程、handler线程,然后等待客户端的连接并处理客户端的请求。


而加载文件系统则是启动过程中的关键步骤,又可以细分为:

  • 加载fsimage文件

  • 加载fsimage的MD5文件并进行比对校验

  • 加载editlog文件

  • checkpoint的保存(可选)

  • 进入安全模式


加载fsimage就是读取fsimage文件中的内容,并以此在内存中构建相关的元数据信息加载editlog则是读取本地editlog文件或到JournalNode上读取editlog文件;checkpoint本质上还是对元数据信息持久化保存,对于HA模式而言,不需要进行checkpoint的保存处理;最后按需进入安全模式,等待dn的注册与块上报,当上报的块信息达到指定比例后(默认为99.9%),延迟一段时间后解除安全模式


需要注意的是:这几个步骤是串行进行的,一个步骤完成后才进行下一个处理动作。


整个启动过程中,耗时的点在于加载文件系统dn注册后的块汇报加载文件系统的耗时在整个启动过程中占50%左右,剩下的50%为dn注册的块汇报处理。http服务和rpc服务的启动几乎不耗时。


【fsimage的格式】


既然加载文件系统占整个启动过程中一半的耗时,有必要先来了解了fsimage文件格式是怎样的,具体的加载过程又是怎样的。


整个fsimage文件由几个部分组成,最前面的是Header头信息,然后是多个section段section之后是一个Summary概要信息以及Summary的长度



header的内容在2.4版本之后均固定为"HDFSIMG1",长度为8字节,同时指明后面的section的编码方式(采用protobuf的方式编码存储)。


summary则记录各个section的名字、在文件中的起始偏移位置以及长度section则保存Hdfs元数据的相关信息,其中最重要的当属INODEINODE_DIR两个section了,通常来说,这两个section占据fsimage的绝大部分空间。


INODE记录了hdfs中包含的所有文件/目录的信息包括名称及可能的各个属性,每个INODE对应一条记录信息;而INDOE_DIR则记录了INODE的父子关系,也就是文件、目录的层级关系,同样也是一条记录对应一条关系信息。有了两个section,就可以构造出完整的文件系统目录树。


读取fsimage文件时,先读文件末尾4字节,得到Summary的起始位置,然后读取Summary的内容,这样就知道每个section的起始位置,长度,因此就可以按需加载各个section的内容了。


另外,section的加载顺序是串行的,即加载INODE_DIR时,必须先完成INODE的加载,否则可能出现找不到对应的inode条目


【如何优化】


从上面fsimage的文件格式可以看出,每个文件的inode在INodeSection中都是一个独立的条目,读fsimage文件时单线程遍历每个条目,并在内存中构造对应的数据结构进行存储。因此,当有海量文件信息存储在fsiamge中时,单线程遍历必然是非常耗时的。这也就是启动耗时长的主要原因。


既然单线程加载很慢,那是否可以调整成多线程加载,每个线程读取其中的一部分,从而加速完成整个INodeSection的加载呢?


实际上,社区版本中的优化就是这么做的,将INodeSeciont拆分成多个带sub后缀的新分区名,同时保留原始的分区信息,同时在summary中增加各个子section的信息



真正读取文件时,使用多线程进行加载,每个线程完成一部分子section的读取,实现读取的加速,同样INODE_DIR也通过多线程并行进行读取。


其中,拆分后的子分区个数由配置项("dfs.image.parallel.target.sections")决定,并行加载的线程数由配置项("dfs.image.parallel.threads")决定。


这样一来,就可以通过多线程并行进行加载INODE和INODE_DIR两个section,每个线程读取一个子section,有效提升加载速度。


除此之外,社区还有两个优化:

一个优化是:fsimage文件md5校验计算和fsimage的加载并行处理,在此之前是串行处理的,详见官方JIRA(HDFS-13694)。


另一个优化是:在加载INodeDirectorySection后,需要更新blocksMap、更新nameCache,然后将inode添加到inode directory的child列表中,优化的逻辑是将这三个操作步骤并行进行处理。


【优化效果】


从官方给出的优化效果来看,数据量在几个亿的级别时,三个优化整体能达到40%-60%的提升(有兴趣的可以去看看社区给出的测试数据)。


而实际测试发现,整体效果差不多是在这个范围内,但具体还会NN所在节点的CPU核数有一定的关系,并行加载时,CPU几乎处于满负荷状态,如果核数不够,那么效果会一般,核数稍微大一些,优化的效果会明显了。


【总结】


好了,小结一下,本文主要讲述了nn的启动流程,分析了主要的耗时点,然后结合fsimage的文件结构,讲述社区的实际优化处理,以及优化后的效果。


如果觉得本文对你有帮助,三连走起(点赞,在看,分享转发),也欢迎加我微信交流~




本文分享自微信公众号 - hncscwc(gh_383bc7486c1a)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接