1. Hadoop 1.x 版本 fsimage和edits合并实现原理 

在NameNode运行期间,HDFS的所有更新操作都是直接写到edits中,久而久之edits文件将会变得很大;虽然这对NameNode运行时候是没有什么影响的,但是我们知道当NameNode重启的时候,NameNode先将fsimage里面的所有内容映像到内存中,然后再一条一条地执行edits中的记录,当edits文件非常大的时候,会导致NameNode启动操作非常地慢,而在这段时间内HDFS系统处于安全模式,这显然不是用户要求的。能不能在NameNode运行的时候使得edits文件变小一些呢?其实是可以的,本文主要是针对Hadoop 1.x版本,说明其是怎么将edits和fsimage文件合并的,Hadoop 2.x版本edits和fsimage文件合并是不同的。
  用过Hadoop的用户应该都知道在Hadoop里面有个SecondaryNamenode进程,从名字看来大家很容易将它当作NameNode的热备进程。其实真实的情况不是这样的。SecondaryNamenode是HDFS架构中的一个组成部分,它是用来保存namenode中对HDFS metadata的信息的备份,并减少namenode重启的时间而设定的!一般都是将SecondaryNamenode单独运行在一台机器上,那么SecondaryNamenode是如何namenode重启的时间的呢?来看看SecondaryNamenode的工作情况:
  (1)、SecondaryNamenode会定期的和NameNode通信,请求其停止使用edits文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;
  (2)、SecondaryNamenode通过HTTP GET方式从NameNode上获取到fsimage和edits文件,并下载到本地的相应目录下;
  (3)、SecondaryNamenode将下载下来的fsimage载入到内存,然后一条一条地执行edits文件中的各项更新操作,使得内存中的fsimage保存最新;这个过程就是edits和fsimage文件合并;
  (4)、SecondaryNamenode执行完(3)操作之后,会通过post方式将新的fsimage文件发送到NameNode节点上
  (5)、NameNode将从SecondaryNamenode接收到的新的fsimage替换旧的fsimage文件,同时将edit.new替换edits文件,通过这个过程edits就变小了!整个过程的执行可以通过下面的图说明:

hdfs检测合并碎文件_fsimage

  在(1)步骤中,我们谈到SecondaryNamenode会定期的和NameNode通信,这个是需要配置的,可以通过core-site.xml进行配置,下面是默认的配置:





  1. <property>


  2. <name>fs.checkpoint.period </name>


  3. <value>3600 </value>


  4. <description>The number of seconds between two periodic checkpoints.


  5. </description>


  6. </property>




  其实如果当fs.checkpoint.period配置的时间还没有到期,我们也可以通过判断当前的edits大小来触发一次合并的操作,可以通过下面配置







  1. <property>


  2. <name>fs.checkpoint.size </name>


  3. <value>67108864 </value>


  4. <description>The size of the current edit log (in bytes) that triggers


  5. a periodic checkpoint even if the fs.checkpoint.period hasn't expired.


  6. </description>


  7. </property>







  当edits文件大小超过以上配置,即使fs.checkpoint.period还没到,也会进行一次合并。顺便说说SecondaryNamenode下载下来的fsimage和edits暂时存放的路径可以通过下面的属性进行配置:







  1. <property>


  2. <name>fs.checkpoint.dir </name>


  3. <value>${hadoop.tmp.dir}/dfs/namesecondary </value>


  4. <description>Determines where on the local filesystem the DFS secondary


  5. name node should store the temporary images to merge.


  6. Ifthisis a comma-delimited list of directories then the image is


  7. replicated in all of the directories for redundancy.


  8. </description>


  9. </property>





  10. <property>


  11. <name>fs.checkpoint.edits.dir </name>


  12. <value>${fs.checkpoint.dir} </value>


  13. <description>Determines where on the local filesystem the DFS secondary


  14. name node should store the temporary edits to merge.


  15. Ifthisis a comma-delimited list of directoires then teh edits is


  16. replicated in all of the directoires for redundancy.


  17. Default value is same as fs.checkpoint.dir


  18. </description>


  19. </property>








从上面的描述我们可以看出,SecondaryNamenode根本就不是Namenode的一个热备,其只是将fsimage和edits合并。其拥有的fsimage不是最新的,因为在他从NameNode下载fsimage和edits文件时候,新的更新操作已经写到edit.new文件中去了。而这些更新在SecondaryNamenode是没有同步到的!当然,如果NameNode中的fsimage真的出问题了,还是可以用SecondaryNamenode中的fsimage替换一下NameNode上的fsimage,虽然已经不是最新的fsimage,但是我们可以将损失减小到最少!

2. 2.X 版本中fsimage和edits合并实现原理 

 我们知道,在Hadoop 2.x中解决了NameNode的单点故障问题;同时SecondaryName已经不用了,而之前的Hadoop 1.x中是通过SecondaryName来合并fsimage和edits以此来减小edits文件的大小,从而减少NameNode重启的时间。而在Hadoop 2.x中已经不用SecondaryName,那它是怎么来实现fsimage和edits合并的呢?首先我们得知道,在Hadoop 2.x中提供了HA机制(解决NameNode单点故障),可以通过配置奇数个JournalNode来实现HA,如何配置今天就不谈了!HA机制通过在同一个集群中运行两个NN(active NN & standby NN)来解决NameNode的单点故障,在任何时间,只有一台机器处于Active状态;另一台机器是处于Standby状态。Active NN负责集群中所有客户端的操作;而Standby NN主要用于备用,它主要维持足够的状态,如果必要,可以提供快速的故障恢复。
  为了让Standby NN的状态和Active NN保持同步,即元数据保持一致,它们都将会和JournalNodes守护进程通信。当Active NN执行任何有关命名空间的修改,它需要持久化到一半以上的JournalNodes上(通过edits log持久化存储),而Standby NN负责观察edits log的变化,它能够读取从JNs中读取edits信息,并更新其内部的命名空间。一旦Active NN出现故障,Standby NN将会保证从JNs中读出了全部的Edits,然后切换成Active状态。Standby NN读取全部的edits可确保发生故障转移之前,是和Active NN拥有完全同步的命名空间状态
  那么这种机制是如何实现fsimage和edits的合并?在standby NameNode节点上会一直运行一个叫做CheckpointerThread的线程,这个线程调用StandbyCheckpointer类的doWork()函数,而doWork函数会每隔Math.min(checkpointCheckPeriod, checkpointPeriod)秒来坐一次合并操作,相关代码如下:


  1. try{

  2. Thread.sleep(1000* checkpointConf.getCheckPeriod());

  3. }catch(InterruptedException ie) {

  4. }


  5. publiclonggetCheckPeriod() {

  6. returnMath.min(checkpointCheckPeriod, checkpointPeriod);

  7. }


  8. checkpointCheckPeriod = conf.getLong(

  9. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_KEY,

  10. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_DEFAULT);


  11. checkpointPeriod = conf.getLong(DFS_NAMENODE_CHECKPOINT_PERIOD_KEY,

  12. DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT);

  13. try{

  14. Thread.sleep(1000* checkpointConf.getCheckPeriod());

  15. }catch(InterruptedException ie) {

  16. }


  17. publiclonggetCheckPeriod() {

  18. returnMath.min(checkpointCheckPeriod, checkpointPeriod);

  19. }


  20. checkpointCheckPeriod = conf.getLong(

  21. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_KEY,

  22. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_DEFAULT);


  23. checkpointPeriod = conf.getLong(DFS_NAMENODE_CHECKPOINT_PERIOD_KEY,

  24. DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT);



上面的checkpointCheckPeriod和checkpointPeriod变量是通过获取hdfs-site.xml以下两个属性的值得到:


  1. <property>

  2. <name>dfs.namenode.checkpoint.period </name>

  3. <value>3600 </value>

  4. <description>The number of seconds between two periodic checkpoints.

  5. </description>

  6. </property>


  7. <property>

  8. <name>dfs.namenode.checkpoint.check.period </name>

  9. <value>60 </value>

  10. <description>The SecondaryNameNode and CheckpointNode will poll the NameNode

  11. every'dfs.namenode.checkpoint.check.period'seconds to query the number

  12. of uncheckpointed transactions.

  13. </description>

  14. </property>



当达到下面两个条件的情况下,将会执行一次checkpoint:


  1. false;

  2. if(uncheckpointed >= checkpointConf.getTxnCount()) {

  3. "Triggering checkpoint because there have been "

  4. " txns since the last checkpoint, which "

  5. "exceeds the configured threshold "

  6. checkpointConf.getTxnCount());

  7. true;

  8. }elseif(secsSinceLast >= checkpointConf.getPeriod()) {

  9. "Triggering checkpoint because it has been "

  10. " seconds since the last checkpoint, which "

  11. "exceeds the configured interval "

  12. true;

  13. }



  当上述needCheckpoint被设置成true的时候,StandbyCheckpointer类的doWork()函数将会调用doCheckpoint()函数正式处理checkpoint。当fsimage和edits的合并完成之后,它将会把合并后的fsimage上传到Active NameNode节点上,Active NameNode节点下载完合并后的fsimage,再将旧的fsimage删掉(Active NameNode上的)同时清除旧的edits文件。步骤可以归类如下:
  (1)、配置好HA后,客户端所有的更新操作将会写到JournalNodes节点的共享目录中,可以通过下面配置


  1. <property>

  2. <name>dfs.namenode.shared.edits.dir </name>

  3. <value>qjournal://XXXX/mycluster </value>

  4. </property>


  5. <property>

  6. <name>dfs.journalnode.edits.dir </name>

  7. <value>/export1/hadoop2x/dfs/journal </value>

  8. </property>



  (2)、Active Namenode和Standby NameNode从JournalNodes的edits共享目录中同步edits到自己edits目录中;
  (3)、Standby NameNode中的StandbyCheckpointer类会定期的检查合并的条件是否成立,如果成立会合并fsimage和edits文件;
  (4)、Standby NameNode中的StandbyCheckpointer类合并完之后,将合并之后的fsimage上传到Active NameNode相应目录中;
  (5)、Active NameNode接到最新的fsimage文件之后,将旧的fsimage和edits文件清理掉;
  (6)、通过上面的几步,fsimage和edits文件就完成了合并,由于HA机制,会使得Standby NameNode和Active NameNode都拥有最新的fsimage和edits文件(之前Hadoop 1.x的SecondaryNameNode中的fsimage和edits不是最新的)

参考文章:

1. http://tech.meituan.com/namenode.html

2.http://tech.meituan.com/namenode-memory-detail.html


版权声明:本文为博主原创文章,转载务必注明出处,否则追求法律责任


1. Hadoop 1.x 版本 fsimage和edits合并实现原理 

在NameNode运行期间,HDFS的所有更新操作都是直接写到edits中,久而久之edits文件将会变得很大;虽然这对NameNode运行时候是没有什么影响的,但是我们知道当NameNode重启的时候,NameNode先将fsimage里面的所有内容映像到内存中,然后再一条一条地执行edits中的记录,当edits文件非常大的时候,会导致NameNode启动操作非常地慢,而在这段时间内HDFS系统处于安全模式,这显然不是用户要求的。能不能在NameNode运行的时候使得edits文件变小一些呢?其实是可以的,本文主要是针对Hadoop 1.x版本,说明其是怎么将edits和fsimage文件合并的,Hadoop 2.x版本edits和fsimage文件合并是不同的。
  用过Hadoop的用户应该都知道在Hadoop里面有个SecondaryNamenode进程,从名字看来大家很容易将它当作NameNode的热备进程。其实真实的情况不是这样的。SecondaryNamenode是HDFS架构中的一个组成部分,它是用来保存namenode中对HDFS metadata的信息的备份,并减少namenode重启的时间而设定的!一般都是将SecondaryNamenode单独运行在一台机器上,那么SecondaryNamenode是如何namenode重启的时间的呢?来看看SecondaryNamenode的工作情况:
  (1)、SecondaryNamenode会定期的和NameNode通信,请求其停止使用edits文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;
  (2)、SecondaryNamenode通过HTTP GET方式从NameNode上获取到fsimage和edits文件,并下载到本地的相应目录下;
  (3)、SecondaryNamenode将下载下来的fsimage载入到内存,然后一条一条地执行edits文件中的各项更新操作,使得内存中的fsimage保存最新;这个过程就是edits和fsimage文件合并;
  (4)、SecondaryNamenode执行完(3)操作之后,会通过post方式将新的fsimage文件发送到NameNode节点上
  (5)、NameNode将从SecondaryNamenode接收到的新的fsimage替换旧的fsimage文件,同时将edit.new替换edits文件,通过这个过程edits就变小了!整个过程的执行可以通过下面的图说明:

hdfs检测合并碎文件_fsimage

  在(1)步骤中,我们谈到SecondaryNamenode会定期的和NameNode通信,这个是需要配置的,可以通过core-site.xml进行配置,下面是默认的配置:




  1. <property>

  2. <name>fs.checkpoint.period </name>

  3. <value>3600 </value>

  4. <description>The number of seconds between two periodic checkpoints.

  5. </description>

  6. </property>




  其实如果当fs.checkpoint.period配置的时间还没有到期,我们也可以通过判断当前的edits大小来触发一次合并的操作,可以通过下面配置






  1. <property>

  2. <name>fs.checkpoint.size </name>

  3. <value>67108864 </value>

  4. <description>The size of the current edit log (in bytes) that triggers

  5. a periodic checkpoint even if the fs.checkpoint.period hasn't expired.

  6. </description>

  7. </property>







  当edits文件大小超过以上配置,即使fs.checkpoint.period还没到,也会进行一次合并。顺便说说SecondaryNamenode下载下来的fsimage和edits暂时存放的路径可以通过下面的属性进行配置:






  1. <property>

  2. <name>fs.checkpoint.dir </name>

  3. <value>${hadoop.tmp.dir}/dfs/namesecondary </value>

  4. <description>Determines where on the local filesystem the DFS secondary

  5. name node should store the temporary images to merge.

  6. Ifthisis a comma-delimited list of directories then the image is

  7. replicated in all of the directories for redundancy.

  8. </description>

  9. </property>


  10. <property>

  11. <name>fs.checkpoint.edits.dir </name>

  12. <value>${fs.checkpoint.dir} </value>

  13. <description>Determines where on the local filesystem the DFS secondary

  14. name node should store the temporary edits to merge.

  15. Ifthisis a comma-delimited list of directoires then teh edits is

  16. replicated in all of the directoires for redundancy.

  17. Default value is same as fs.checkpoint.dir

  18. </description>

  19. </property>








从上面的描述我们可以看出,SecondaryNamenode根本就不是Namenode的一个热备,其只是将fsimage和edits合并。其拥有的fsimage不是最新的,因为在他从NameNode下载fsimage和edits文件时候,新的更新操作已经写到edit.new文件中去了。而这些更新在SecondaryNamenode是没有同步到的!当然,如果NameNode中的fsimage真的出问题了,还是可以用SecondaryNamenode中的fsimage替换一下NameNode上的fsimage,虽然已经不是最新的fsimage,但是我们可以将损失减小到最少!

2. 2.X 版本中fsimage和edits合并实现原理 

 我们知道,在Hadoop 2.x中解决了NameNode的单点故障问题;同时SecondaryName已经不用了,而之前的Hadoop 1.x中是通过SecondaryName来合并fsimage和edits以此来减小edits文件的大小,从而减少NameNode重启的时间。而在Hadoop 2.x中已经不用SecondaryName,那它是怎么来实现fsimage和edits合并的呢?首先我们得知道,在Hadoop 2.x中提供了HA机制(解决NameNode单点故障),可以通过配置奇数个JournalNode来实现HA,如何配置今天就不谈了!HA机制通过在同一个集群中运行两个NN(active NN & standby NN)来解决NameNode的单点故障,在任何时间,只有一台机器处于Active状态;另一台机器是处于Standby状态。Active NN负责集群中所有客户端的操作;而Standby NN主要用于备用,它主要维持足够的状态,如果必要,可以提供快速的故障恢复。
  为了让Standby NN的状态和Active NN保持同步,即元数据保持一致,它们都将会和JournalNodes守护进程通信。当Active NN执行任何有关命名空间的修改,它需要持久化到一半以上的JournalNodes上(通过edits log持久化存储),而Standby NN负责观察edits log的变化,它能够读取从JNs中读取edits信息,并更新其内部的命名空间。一旦Active NN出现故障,Standby NN将会保证从JNs中读出了全部的Edits,然后切换成Active状态。Standby NN读取全部的edits可确保发生故障转移之前,是和Active NN拥有完全同步的命名空间状态
  那么这种机制是如何实现fsimage和edits的合并?在standby NameNode节点上会一直运行一个叫做CheckpointerThread的线程,这个线程调用StandbyCheckpointer类的doWork()函数,而doWork函数会每隔Math.min(checkpointCheckPeriod, checkpointPeriod)秒来坐一次合并操作,相关代码如下:


  1. try{

  2. Thread.sleep(1000* checkpointConf.getCheckPeriod());

  3. }catch(InterruptedException ie) {

  4. }


  5. publiclonggetCheckPeriod() {

  6. returnMath.min(checkpointCheckPeriod, checkpointPeriod);

  7. }


  8. checkpointCheckPeriod = conf.getLong(

  9. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_KEY,

  10. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_DEFAULT);


  11. checkpointPeriod = conf.getLong(DFS_NAMENODE_CHECKPOINT_PERIOD_KEY,

  12. DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT);

  13. try{

  14. Thread.sleep(1000* checkpointConf.getCheckPeriod());

  15. }catch(InterruptedException ie) {

  16. }


  17. publiclonggetCheckPeriod() {

  18. returnMath.min(checkpointCheckPeriod, checkpointPeriod);

  19. }


  20. checkpointCheckPeriod = conf.getLong(

  21. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_KEY,

  22. DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_DEFAULT);


  23. checkpointPeriod = conf.getLong(DFS_NAMENODE_CHECKPOINT_PERIOD_KEY,

  24. DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT);



上面的checkpointCheckPeriod和checkpointPeriod变量是通过获取hdfs-site.xml以下两个属性的值得到:


  1. <property>

  2. <name>dfs.namenode.checkpoint.period </name>

  3. <value>3600 </value>

  4. <description>The number of seconds between two periodic checkpoints.

  5. </description>

  6. </property>


  7. <property>

  8. <name>dfs.namenode.checkpoint.check.period </name>

  9. <value>60 </value>

  10. <description>The SecondaryNameNode and CheckpointNode will poll the NameNode

  11. every'dfs.namenode.checkpoint.check.period'seconds to query the number

  12. of uncheckpointed transactions.

  13. </description>

  14. </property>



当达到下面两个条件的情况下,将会执行一次checkpoint:


  1. false;

  2. if(uncheckpointed >= checkpointConf.getTxnCount()) {

  3. "Triggering checkpoint because there have been "

  4. " txns since the last checkpoint, which "

  5. "exceeds the configured threshold "

  6. checkpointConf.getTxnCount());

  7. true;

  8. }elseif(secsSinceLast >= checkpointConf.getPeriod()) {

  9. "Triggering checkpoint because it has been "

  10. " seconds since the last checkpoint, which "

  11. "exceeds the configured interval "

  12. true;

  13. }



  当上述needCheckpoint被设置成true的时候,StandbyCheckpointer类的doWork()函数将会调用doCheckpoint()函数正式处理checkpoint。当fsimage和edits的合并完成之后,它将会把合并后的fsimage上传到Active NameNode节点上,Active NameNode节点下载完合并后的fsimage,再将旧的fsimage删掉(Active NameNode上的)同时清除旧的edits文件。步骤可以归类如下:
  (1)、配置好HA后,客户端所有的更新操作将会写到JournalNodes节点的共享目录中,可以通过下面配置


  1. <property>

  2. <name>dfs.namenode.shared.edits.dir </name>

  3. <value>qjournal://XXXX/mycluster </value>

  4. </property>


  5. <property>

  6. <name>dfs.journalnode.edits.dir </name>

  7. <value>/export1/hadoop2x/dfs/journal </value>

  8. </property>



  (2)、Active Namenode和Standby NameNode从JournalNodes的edits共享目录中同步edits到自己edits目录中;
  (3)、Standby NameNode中的StandbyCheckpointer类会定期的检查合并的条件是否成立,如果成立会合并fsimage和edits文件;
  (4)、Standby NameNode中的StandbyCheckpointer类合并完之后,将合并之后的fsimage上传到Active NameNode相应目录中;
  (5)、Active NameNode接到最新的fsimage文件之后,将旧的fsimage和edits文件清理掉;
  (6)、通过上面的几步,fsimage和edits文件就完成了合并,由于HA机制,会使得Standby NameNode和Active NameNode都拥有最新的fsimage和edits文件(之前Hadoop 1.x的SecondaryNameNode中的fsimage和edits不是最新的)

参考文章:

1. http://tech.meituan.com/namenode.html

2.http://tech.meituan.com/namenode-memory-detail.html