NamNode

NameNode 的主要作用是

  1. 负责管理文件系统的命名空间、集群配置信息和存储块的复制;
  2. 维护着整个文件系统的文件目录树和文件根目录的元信息和每个文件对应的数据块列表;
  3. 接收用户的操作请求;
  4. 管理文件与block之间的关系,block与DataNode之间的关系;

NameNode 的启动流程为:

  1. Loading fsimage - 从fsimage file中读取最新的文件系统的元数据快照(最近生成的fsimage_xx)
  2. Loading edits - 读取包含fsimage_xx之后的所有tx的edit logs并将edit logs中的操作从新操作一遍更新到元数据中,则此时NN更新到上次停止时的状态。
  3. checkpoint - 将当前状态写入新的checkpoint中,即产生一个新的fsimage_xx文件
  4. Safe mode - 等待各个datanodes report各自的block信息,形成blockMap,然后退出安全模式。

此时NN启动结束,等待接受用户的操作请求,并把各种操作写入新的edit log中,定期进行checkpoint,对元数据进行快照。

NameNode 元数据

NameNode的所有操作及整个集群的状态都存储在_元数据_中。NN的元数据存储是由fsimage和edits文件组成。fsimage存放上次checkpoint生成的文件系统元数据,Edits存放文件系统_操作日志_。checkpoint的过程,就是合并fsimage和Edits文件,然后生成最新的fsimage的过程。

NameNode在执行HDFS客户端提交的创建文件或者移动文件这样的_写操作_的时候,会首先把这些操作记录在Edit Log 文件之中,然后再更新内存中的文件系统镜像。内存中的_文件系统镜像_用于NameNode向客户端提供_读服务_,而 EditLog仅仅只是在数据恢复的时候起作用。记录在 EditLog之中的每一个操作又称为一个事务,每个事务有一个整数形式的事务id作为编号。EditLog会被切割为很多段,每一段称为一个Segment。正在写入的EditLog Segment处于in-progress状态,其文件名形如edits_inprogress_${start_txid},其中${start_txid}表示这个segment的起始事务id。而已经写入完成的EditLog Segment处于finalized状态,其文件名形如edits_${start_txid}-${end_txid},其中${start_txid}表示这个segment的起始事务id,${end_txid}表示这个segment 的结束事务id。

NameNode会定期对内存中的文件系统镜像进行checkpoint操作,在磁盘上生成FSImage文件,FSImage文件的文件名形如fsimage_${end_txid},其中${end_txid}表示这个fsimage文件的结束事务id。在NameNode启动的时候会进行数据恢复,首先把FSImage文件加载到内存中形成文件系统镜像,然后再把EditLog之中__FsImage的结束事务id之后的EditLog__回放到这个文件系统镜像上。

元数据在磁盘中的目录结构

NameNode中dfs.namenode.name.dir下的元数据

NameNode元数据会周期性的固化到磁盘,所在磁盘目录是在hdfs-site.xml中由dfs.namenode.name.dir配置的。目录结构如下:

1
2
3
> ll $dfs.namenode.name.dir
drwxrwxr-x 2 hadoop hadoop 4096 Aug 1 19:03 current
-rw-rw-r-- 1 hadoop hadoop 14 Jul 29 15:49 in_use.lock

current里的内容如下:
current目录

上面是将fsimage和edits都放在一个目录中,也可以通过配置将fsimage和edits分别放在不同的目录中。下面就具体介绍下目录中各个文件的作用:

  • in_use.lock – 看名字可以得知这是一个锁文件,由NameNode持有,用来阻止多个NameNode同时修改该目录
  • VERSION - Java属性文件,内容大致如下
1
2
3
4
5
6
7
#Fri Jul 29 15:50:00 CST 2016
namespaceID=1793378918
clusterID=CID-0bcbc37e-90e2-40c5-91c2-101db9fc4f9b
cTime=0
storageType=NAME_NODE
blockpoolID=BP-2041947102-172.16.2.126-1451322470514
layoutVersion=-60
  • layoutVersion – HDFS元数据格式化的版本。如果给HDFS添加新的feature而需要改变元数据的格式化版本,则改变此属性,版本号是递减的。
  • storageType – 说明这个文件存储的是什么进程的数据结构信息。(NAME_NODE或者JOURNAL_NODE,JOURNAL_NODE是JouranlNode的元数据,在DataNode中是DATA_NODE)
  • cTime – 文件系统创建的时间,随着HDFS的升级而改变。(这里没有对HDFS升级,则记录值为0)
  • namespaceID/clusterID/blockpoolID – 这些都唯一标识了HDFS集群。这些标识主要是用来防止DataNode注册到别的其它集群的NameNode中。这些标识符在联邦部署中尤其重要。在联邦模式下,每个NameSpace都唯一的namespaceID,管理着对应的唯一blockpoolID,而clusterID则是整个联邦集群的唯一逻辑单元,集群中所有的节点都相同。
  • seen_txid – 这个文件里记录了最后一次checkpoint(将edits合并到fsimage中)或者edit回滚(将edits_inprogress_xx文件回滚成一个新的edits文件)之后的transactionID。注意这里记录的不是NameNode接受的最后一个transactionID,此文件不会在每次transaction都会更新,只在checkpoint和edit回滚时更新**(但是通过观察2.6.0版本的本地元数据磁盘目录中记录的此值,是实时更新的,每次transaction都会更新,这个具体随后更代码看下什么情况,在此只做记录下)**。此文件的目的是在NameNode启动过程中发现edits文件丢失的情况。如果edits文件丢失,NameNode启动的过程中加载fsimage文件,此时fsimage并不是最新的NameNode状态,而此时又缺失一些edits文件,但NameNode并不知道,而是正常启动了,此时就会造成一些数据丢失。seen_txid能用来防止这种情况发生,如果发现seen_txid中记录的值和edits的值不一样,则启动失败。

JournalNode下的元数据

在HA模式下,edits由一组独立的守护进程JournalNodes进行收集。JournalNode的元数据目录配置在hdfs-site.xml的dfs.journalnode.edits.dir。JournalNode的元数据包含一个VERSION文件,多个edits_xx文件和一个edits_inprogress_xx,还包含一些与HA实现相关的文件,这些文件主要是为了防止脑裂,但是JournalNode并不包含fsimage和seen_txid

下面主要介绍下与NameNode元数据不一样的文件:

  • committed-txid – 记录由NameNode提交的最后一个transaction ID
  • last-promised-epoch – 这个文件记录了epoch,epoch是一个单调递增的数字。当standby变为active时,JournalNode会会增加epoch并存储。NameNode主要通过该值来告诉JournalNode谁是active,小于该值的NameNode禁止对JournalNode元数据写操作,写请求被忽略。
  • last-writer-epoch – 和上面的值类似,该文件记录下最后一次发生写操作的epoch。
  • paxos – 此目录包含一些临时文件,主要在实现paxos分布式算法协议中使用。这个目录通常是空的。

Checkpoint

每个写操作都会写入Edit log中,随着时间的积累edit log会变的很大,极端情况下不仅会占满整个磁盘,而且在NN启动的时候会延长启动时间,因为NN需要将edits log中的操作重新执行一遍。这就需要checkpoint定期对元数据进行合并。

Checkpoint主要是将fsimage和edit log的内容进行合并生成一个新的fsimage。这样在NN启动的时候就不用将巨大的edits里的事务再次执行一遍了,而是直接加载合并之后的新fsimage,然后重新执行未被合并的edits文件就可以了。

创建新fsimage的过程需要大量的I/O、内存等资源,而且namesystem在Checkpoint的时候会限制用户的访问。则NN将Checkpoint过程放在SecondaryNameNode或者StandbyNameNode中。

Checkpoint的触发条件有两个,满足其中一个即可:

  1. 两次checkpoint的时间间隔达到阈值,由属性dfs.namenode.checkpoint.period控制,默认是3600s
  2. 新生成的edit log中积累的事务数量达到了阈值,由属性dfs.namenode.checkpoint.txns控制,默认1000000

SecondaryNameNode或者StandbyNameNode周期性的去检查是否符合触发Checkpoint的条件,间隔周期是由dfs.namenode.checkpoint.check.period控制的,默认是60s

Fsimage回滚条件

  1. fsimage会在每次checkpoint时生成一个新的fsimage
  2. NN重启的时候也会生成一个新的fsimage

fsimage默认会保存两个,由属性dfs.namenode.num.checkpoints.retained控制

Edits log回滚条件

  1. NameNode(active)周期性的检查当前的事务数是否超过了edits回滚阈值。
    间隔周期是由dfs.namenode.edit.log.autoroll.check.interval.ms控制,默认是300000ms。
    回滚的阈值是dfs.namenode.edit.log.autoroll.multiplier.thresholddfs.namenode.checkpoint.txns的乘积,dfs.namenode.edit.log.autoroll.multiplier.threshold默认是2.0f
  2. 在HA模式下,standby NN会周期的让active NN对edits进行回滚,间隔周期由dfs.ha.log-roll.period
    控制,默认是120s

standby NN之所以周期的让active NN回滚edits log是因为standby NN不会读取_inprogress_的edits,只是周期(dfs.ha.tail-edits.period,默认是60s)的去检测已经完成的edits文件,并将该edits文件通过JournalNode读取到内存更新fsimage在内存中的状态。

HA模式下,client只和active进行通信,将写操作信息分别写入本地的edits中和JournalNode中的edits中,standby NN周期的去JournalNode中读取进行同步。只有在active宕机之后,standby才对外提供服务,平时只是实现了active的热备

edits log默认会保存dfs.namenode.num.extra.edits.retained条事务,默认是1000000条

查看fsimage和edits内容的命令

查看fsimage命令

1
hdfs oiv -p XML -i fsimage -o fsimage.xml

-i是输入的fsimage文件名,-o是输出的文件名,-p是输出的格式。具体的细节可以查看官网或者使用help命令查看。

查看edits命令

1
hdfs oev -i edits -o edits.xml