Namenode做block Recovery过程详细剖析

来源:互联网 发布:spps怎么实现数据筛选 编辑:程序博客网 时间:2024/04/20 07:26
  • hdfs为什么会做block recovery

说HDFS的block recovery,其实就是Namenode认为该block的状态需要发生一些变化,其原信息和数据都需要做一些相应的调整(或恢复),原信息的调整在namenode上,而由于数据本身是存储在datanode的磁盘上的,所以数据本身的调整其实是由datanode来完成。

那么,为什么Namenode会认为某个block的状态“需要发生一些改变呢”?这就要从代码中实际触发block recovery的入口着手。实际上,在namenode中,namenode并不是直接触发block recovery的,因为要对block做recovery操作,刚才上面提过,实际上涉及到两个部分的修改:

    1. block原信息的修改 —— 这部分的修改在namenode中直接就可以完成
    2. block数据本身的修改 —— 由于存储block实际上是datanode,所以,namenode就需要“告诉”datanode,让datanode来完成其上该block的recovery操作

所以,实际上namenode是要向datanode“发送block recovery命令”来达到上述第二个修改,也就是block数据本身的修改的目的。
而“命令”是如何发送给datanode的呢?这就涉及到HDFS中namenode和datanode的通信机制。我们都知道在HDFS中,datanode是会每隔几秒钟向namenode定期的发送心跳,namenode通过监控每隔datanode的两次心跳间隔来判断该datanode是否还活着,超过一定的时间间隔(默认10分30秒),就会认为该datanode已经死掉了。但是很多人不知道的是,datanode每次心跳发送到namenode,namenode是会返回给datanode一个“命令集(cmds)”的,这个命令集就是namenode需要datanode执行的某些操作,比如
    1. 将该datanode上的某个block拷贝到其他datanode上去的DNA_TRANSFER命令
    2. 将该datanode上的某个block从物理磁盘上删除的DNA_TRANSFER命令
    3. 停止该datanode的DNA_SHUTDOWN命令
    4. 对某个block进行block recovery的DNA_RECOVERBLOCK命令
    5. …...

从上可以看出,从heartbeat的返回命令集中,就包括了对某个block进行recovery的命令。所以,datanode某个block进行recovery操作的动作,实际上是来自namenode的指令。也就是说,namenode认为这个block需要做recovery了,并且这个block在某几个datanode上保存,那么namenode就会在这几个datanode的heartbeat发送过来后,给这几个datanode返回指令集,指令集中就包括对这个block进行recovery的指令。于是datanode接受到这个指令后,对block进行数据本身的recovery操作。
明白了datanode是如何会做block的recovery操作后,剩下的问题就还剩下两个了:
  1. namenode为什么会“认为某个block需要做recovery操作”?
  2. datanode在recovery一个block的时候,实际上到底对这个block做了些什么?

  • namenode为什么会“认为某个block需要做recovery操作”?(什么情况下会做block recovery)

这个问题其实就是namenode对block做recovery的入口问题。什么情况下namenode会认为某个block需要进行recovery操作呢?从namenode的代码内部实现层层挖下去,就会发现,其实入口只有一个,就是namenode在对某个文件的lease进行release的时候。

                                                                                           于是,新的问题又来了,什么叫做“对某个文件的Lease进行release”?由于篇幅原因,这里不打算深入介绍namenode中的Lease原理和实现机制,只是简单的做一个简介:Namenode中的所谓Lease,其实就是namenode中用来标识某个Client端对HDFS中的某个文件正在进行写入操作的一个写锁。由于HDFS是一次写入,多次读取的系统,不允许对文件内容进行modify(0.20开始HDFS支持对文件的append,但仍然不支持对文件中间的某些内容进行修改),也不允许多个用户(客户端)对同一个文件同时进行修改,所以,通一时间,只能有一个客户端对一个文件的最后一个block进行写入,而如果其他客户端想在同一时间对该文件进行写入,就是不允许的。这个排他的机制,就是利用Lease来保证的。也就是说,某个客户端要对文件进行写入,必须先申请到该文件的Lease,一旦申请到后,就会允许对该文件的block进行数据写入,而如果有其他客户端已经持有这个文件的Lease,就不能再写入了。

知道了什么是Lease以后,再来解释什么叫做“对一个Lease进行release”。刚才有提到,一个Lease实际上相当于HDFS中一个文件的写锁,对应一个客户端。那么,如果一个客户端(假设叫ClientA)在持有某个文件的Lease情况下,客户端在写入数据过程中发生宕机,或者其他事故,导致无法继续对文件进行写入,会产生什么情况呢?这种情况下,由于该文件的Lease是由namenode来维护的,也就是说,此时namenode认为该文件正在被ClientA持有,所以namenode就不允许其他client对文件进行写入,但此时ClientA已经挂了,但namenode不知道,这就会导致其他所有的Client都无法对文件进行写入了。这其实是不对的。所以,namenode中对某个client对应某个文件的Lease是有一个限期的,一旦过了这个限期,该Lease没有发生任何改变(比如更新时间),没有写入任何数据,那么namenode就认为该lease对应的客户端发生了异常,需要在namenode端对这个Lease进行释放,一遍其他的client能够对文件进行写入操作。这个过程就叫做”对一个Lease进行release“操作。

至此,就明白了,其实namenode中,对block做recovery的入口只有一个,就是namenode对某个Lease进行释放的时候触发的。该函数调用在 NameNode.FSNamesystem.internalReleaseLeaseOne(Lease, filePath)。


  • datanode在recovery一个block的时候,实际上到底对这个block做了些什么?(datanode做block recovery的详细过程) 
由于一个客户端(DFSClient)通常会不止一次写一个文件,可能会些多个,所以一个Lease对象在namenode中通常代表一个客户端对一些文件的文件写锁,所以其实,对一个文件的lease的释放并不一定会删除掉namenode中该文件对应的lease对象,但是会释放这个文件在lease中的记录。所以一次internalReleaseLeaseOne(Lease,filePath)的调用的参数包括一个lease和一个文件名,就是这个原因。实际上,一次internalReleaseLeaseOne的过程就是namenode做了这么一件事情:
1, 从namenode内存中找到该filePath对应的文件INode,通常这个时候该INode是一个INodeFileUnderConstruction的实例,表示这个文件是正在被写入,还没有complete的一个文件。
2, 找到这个INodeFileUnderConstruction以后,查看该文件的block队列是否为空,如果为空,表示这个文件是个空文件,那么直接将该文件complete,删除其对应的lease记录,然后返回。
3, 如果该文件的block队列不为空,那么获取该文件的block队列,并找到该队列的最后一个block,将该block的最后一个block对应的datanode设置为该文件的targets,这个操作的原因在于:由于HDFS的文件只能向最后一个block写入输入,所以lease过期肯定是出了最后一个block有问题外,其他block应该都是完整的,所以获取最后一个block。而targets表示最后一个block应该保存在哪几个datanode上,该targets是一个datanode队列,也就是说,namenode知道这最后一个block是在这么几台datanode上,以便向这几个datanode发送block recovery命令。
4, 在targets队列中选择一个datanode作为primary datanode
5, 将block recovery命令保存在namenode内存中对应的这个primary datanode的队列中,等待该datanode的下一个heartbeat,然后在heartbeat的response中将block recovery命令发送给这个datanode,让datanode完成物理block的recovery操作。

到这里,namenode对一个文件的block recovery操作就告一段落,namenode接下来要做的是等待接收到block recovery命令的datanode对这个block进行recovery的物理操作,然后汇报状态。

接下来的问题是:datanode接收到namenode发送来的block recovery命令后,会做一些什么?
datanode在接收到block recovery命令后(通常接收到这命令的都是文件最后一个block对应的datanode targets数组中的primary datanode),就会对这个block进行真正的recovery操作。具体的recovery操作流程如下:
1, 由于block recovery 是由primary datanode发起,但该recovery操作需要在三个datanode上对该block进行操作(假设文件副本为3),所以primary datanode接收到命令的时候同时还收到了该block的targets datanode数组(其中就包括该datanode自身)
2, primary datanode遍历targets datanode数组,对每一个datanode,向其发送一个start block recovery的指令。如果是其自身,则直接执行该指令。
3, start block recovery指令会在datanode的磁盘中找到该block的物理块,并确认该block对应的验证信息和meta信息正确,并返回一个BlockRecord对象,表示这个block正在被recovery。
4,对每个BlockRecord,查看keepLength标志位是否为true,如果为true,则只recovery blocksize 跟 namenode中记录的blocksize一致的block,否则全部都算。
5, 对每个物理块,一旦真正开始recovery操作,则进行如下操作:在该datanode上找到该block,同时找到这个block对应的meta文件(每一个block都对应一个meta文件,用来记录该block的验证码等原信息),更新该block的stamp号(表示该block已经被修改过一次),如果需要recovery成的block的size 小于实际的block的size,则将实际的block截断成其需要的大小,并更新meta文件和验证信息。
6, 最后,primary datanode向namenode汇报本次recovery block的信息,如新的block stamp变成了多少,block size被修改成了多少等,namenoe相应的更新这些信息。

原文地址:http://blog.csdn.net/ae86_fc/article/details/6619278
原创粉丝点击