我们来看一下升级/回滚/提交时的DataNode上会发生什么(在类DataStorage中实现)。
前面我们提到过VERSION文件,它保存了一些文件系统的元信息,这个文件在系统升级时,会发生对应的变化。
升级时,NameNode会将新的版本号,通过DataNode的登录应答返回。DataNode收到以后,会将当前的数据块文件目录改名,从current改名为previous.tmp,建立一个snapshot,然后重建current目录。重建包括重建VERSION文件,重建对应的子目录,然后建立数据块文件和数据块元数据文件到previous.tmp的硬连接。建立硬连接意味着在系统中只保留一份数据块文件和数据块元数据文件,current和previous.tmp中的相应文件,在存储中,只保留一份。当所有的这些工作完成以后,会在current里写入新的VERSION文件,并将previous.tmp目录改名为previous,完成升级。
了解了升级的过程以后,回滚就相对简单。因为说有的旧版本信息都保存在previous目录里。回滚首先将current目录改名为removed.tmp,然后将previous目录改名为current,最后删除removed.tmp目录。
提交的过程,就是将上面的previous目录改名为finalized.tmp,然后启动一个线程,将该目录删除。
下图给出了上面的过程:
源代码分析(一一)%20-%20-%20JavaEye技术网站.mht!http://caibinbupt.javaeye.com/upload/attachment/54561/db8038d0-d07a-3c28-80d4-9202bc877ae6.jpg">
需要注意的是,HDFS的升级,往往只是支持从某一个特点的老版本升级到当前版本。回滚时能够恢复到的版本,也是previous中记录的版本。
下面我们继续分析DataNode。
文字分析完DataNode存储在文件上的数据以后,我们来看一下运行时对应的数据结构。从大到小,Hadoop中最大的结构是Storage,最小的结构,在DataNode上是block。
类Storage保存了和存储相关的信息,它继承了StorageInfo,应用于DataNode的DataStorage,则继承了Storage,总体类图如下:
StorageInfo包含了3个字段,分别是layoutVersion:版本号,如果Hadoop调整文件结构布局,版本号就会修改,这样可以保证文件结构和应用一致。namespaceID是Storage的ID,cTime,creation time。
和StorageInfo相比,Storage就是个大家伙了。
Storage可以包含多个根(参考配置项dfs.data.dir的说明),这些根通过Storage的内部类StorageDirectory来表示。StorageDirectory中最重要的方法是analyzeStorage,它将根据系统启动时的参数和我们上面提到的一些判断条件,返回系统现在的状态。StorageDirectory可能处于以下的某一个状态(与系统的工作状态一定的对应):
NON_EXISTENT:指定的目录不存在;
NOT_FORMATTED:指定的目录存在但未被格式化;
COMPLETE_UPGRADE:previous.tmp存在,current也存在
RECOVER_UPGRADE:previous.tmp存在,current不存在
COMPLETE_FINALIZE:finalized.tmp存在,current也存在
COMPLETE_ROLLBACK:removed.tmp存在,current也存在,previous不存在
RECOVER_ROLLBACK:removed.tmp存在,current不存在,previous存在
COMPLETE_CHECKPOINT:lastcheckpoint.tmp存在,current也存在
RECOVER_CHECKPOINT:lastcheckpoint.tmp存在,current不存在
NORMAL:普通工作模式。
StorageDirectory处于某些状态是通过发生对应状态改变需要的工作文件夹和正常工作的current夹来进行判断。状态改变需要的工作文件夹包括:
previous:用于升级后保存以前版本的文件
previous.tmp:用于升级过程中保存以前版本的文件
removed.tmp:用于回滚过程中保存文件
finalized.tmp:用于提交过程中保存文件
lastcheckpoint.tmp:应用于从NameNode中,导入一个检查点
previous.checkpoint:应用于从NameNode中,结束导入一个检查点
有了这些状态,就可以对系统进行恢复(通过方法doRecover)。恢复的动作如下(结合上面的状态转移图):
COMPLETE_UPGRADE:mvprevious.tmp -> previous
RECOVER_UPGRADE:mv previous.tmp -> current
COMPLETE_FINALIZE:rm finalized.tmp
COMPLETE_ROLLBACK:rm removed.tmp
RECOVER_ROLLBACK:mv removed.tmp -> current
COMPLETE_CHECKPOINT:mv lastcheckpoint.tmp -> previous.checkpoint
RECOVER_CHECKPOINT:mv lastcheckpoint.tmp -> current
我们以RECOVER_UPGRADE为例,分析一下。根据升级的过程,
1. current->previous.tmp
2. 重建current
3. previous.tmp->previous
当我们发现previous.tmp存在,current不存在,我们知道只需要将previous.tmp改为current,就能恢复到未升级时的状态。
StorageDirectory还管理着文件系统的元信息,就是我们上面提过StorageInfo信息,当然,StorageDirectory还保存每个具体用途自己的信息。这些信息,其实都存储在VERSION文件中,StorageDirectory中的read/write方法,就是用于对这个文件进行读/写。下面是某一个DataNode的VERSION文件的例子:
配置文件代码
#Fri Nov 14 10:27:35 CST 2008
namespaceID=1950997968
storageID=DS-697414267-127.0.0.1-50010-1226629655026
cTime=0
storageType=DATA_NODE
layoutVersion=-16
对StorageDirectory的排他操作需要锁,还记得我们在分析系统目录时提到的in_use.lock文件吗?它就是用来给整个系统加/解锁用的。StorageDirectory提供了对应的lock和unlock方法。
分析完StorageDirectory以后,Storage类就很简单了。基本上都是对一系列StorageDirectory的操作,同时Storage提供一些辅助方法。
DataStorage是Storage的子类,专门应用于DataNode。上面我们对DataNode的升级/回滚/提交过程,就是对DataStorage的doUpgrade/doRollback/doFinalize分析得到的。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。