大家都知道,在HDFS的集群中有三类节点:NameNode、SecondaryNameNode和DataNode,同时在集群中只有一个NameNode节点,一个SecondaryNameNode节点,剩余的就都是DataNode节点(当然,集群中也可以同时存在多个SecondaryNameNode节点,但这没多大必要,一方面会增加NameNode节点的压力,使其忙于元数据的传输与接收、日志的传输与切换而导致性能的下降,另一方面NameNode节点并不支持做并发checkpoint)。这中master-slave架构虽然简单,却会存在一个致命的问题,那就NameNode节点的单点故障问题(single point of failure),尽管它发生的概率比较小,但对于系统维护人员来说是不容忽视的问题。当然本文不会讨论有关NameNode节点单点故障的社区解决方案,而是主要讲解SecondaryNameNode节点(从NameNode)在HDFS中扮演了怎样的角色?
SecondaryNameNode节点启动之后会不断的对NameNode节点保存的元数据进行备份(定时备份),具体的说来就是:SecondaryNameNode的run方法每隔一段时间就会执行doCheckpoint()方法,SecondaryNameNode的主要工作都在这个方法里。这个方法会从NameNode上取下FSImage和操作日志(当然也包括版本文件和fstime),然后在本地合并,然后再把合并后的FSImage传回NameNode。这样既可以保存一个NameNode上的数据备份,又可以为NameNode节点分担一部分压力。具体的流程如下:
1.调用startCheckpoint,为接下来的工作准备空间。首先存放FSImage和EditsLog的目录分别由配置文件中的fs.checkpoint.dir项和fs.checkpoint.edits.dir项来设置,然后会分别对这两类目录进行检查和恢复,对于已经存在的chechpoint要将它们设置成为lastCheckpoint;
2. 创建RPC客户端,用于和NameNode节点通信;
3.在SecondaryNameNode节点上开启Http服务,主要用来向NameNode节点传输合并好的元数据文件FSImage;
4.远程调用NameNode的rollEditLog方法,让NameNode停止向edits上写操作日志,而是将新产生的日志转写到临时日志文件edits.new上。同时,NameNode端的FSImage检查点状态要设置为ROLLED_EDITS。最后会返回一个检查点签名CheckpointSignature;
5.通过NameNode开启的Http服务从NameNode上下载FSImage和对应的操作日志,之后设置本地的检查点状态设置为UPLOAD_DONE;
6.加载下载的FSImage和操作日志,从而合并成一个新的FSImage;
7.通知NameNode新的FSImage文件已经合并好了,然后NameNode节点通过SecondaryNameNode节点的http服务来下载新的FSImage;
8.远程调用NameNode的rollFsImage,来根据下载的最新FSImage替换原来的FSImage,临时日志文件edits.new重命名为edits;
9.结束本地的一次doCheckpoint。
还是来整一张图吧!(csdn上传图片绝对是垃圾,一张244kb的图片整了半个小时愣是没上传上去!!!)
在这里,我还学要补充的一点就是SecondaryNameNode节点备份的时机,在run的循环方法中,当满足两种情况中的任意一个,SecondaryNameNode节点都会开始备份,这两种情况是:一.设定的间隔时间到了,这个时间可以通过配置文件中fs.checkpoint.period项来设置;二.操作日志文件的大小达到了checkpointSize,这个值也可以通过配置文件中fs.checkpoint.size项来设置(需要远程调用getEditLogSize()方法)。SecondaryNameNode节点执行checkpoing的核心代码如下:
/**
* 对主节点上的元数据做一次checkpoint
*/
void doCheckpoint() throws IOException {
// Do the required initialization of the merge work area.
startCheckpoint();
//通知主节点将操作日志切换到edits.new,并获取一张签证,它表示了当前元数据的状态
CheckpointSignature sig = (CheckpointSignature)namenode.rollEditLog();
// error simulation code for junit test
if (ErrorSimulator.getErrorSimulation(0)) {
throw new IOException("Simulating error0 " +
"after creating edits.new");
}
downloadCheckpointFiles(sig); //从主节点下载此次checkpoint时的元数据及操作日志
doMerge(sig); //合并元数据及操作日志
//
// Upload the new image into the NameNode. Then tell the Namenode
// to make this new uploaded image as the most current image.
//
putFSImage(sig);
// error simulation code for junit test
if (ErrorSimulator.getErrorSimulation(1)) {
throw new IOException("Simulating error1 " +
"after uploading new image to NameNode");
}
//current/edits.new------->/current/edits
//current/fsimage.ckpt------->/current/fsimage
namenode.rollFsImage();
//
checkpointImage.endCheckpoint();
LOG.info("Checkpoint done. New Image Size: "
+ checkpointImage.getFsImageName().length());
}
为了保证在checkpoint过程中异常恢复及一致性,NameNode节点维护了一个对应的状态机: