hdfs的数据是以block为单位存储的,所以了解block的结构对理解hdfs的工作机制非常重要。

先来看一下Block类,它含有三个成员:blockId,numBytes和generationStamp。numBytes即block的大小,而另外两个分别是什么呢?blockId是block的标识符,可以从block文件名中看到,例如${hadoop.tmp.dir}/dfs/data/current/blk_826540629399449945,这一串数字就是blockId。同目录下另一个meta文件,如blk_826540629399449945_1017.meta,1017即是generationStamp。从Block类本身可以看到,generationStamp在compare、equals等操作上起到一个对blockId的辅助作用,由此猜测多个blocks可能拥有相同的blockId,彼此的generationStamp不同。

根据[1],早期block id是一个64位数随机数。当时实现比较简单,并没有判重,所以如果两个block碰巧得到同样的block id,系统会误认为是多余的备份block,而将其中一些删除。这样这个block很有可能出错,包含它的文件则损坏。解决的办法有两个,一是记录好所有使用过的block id,以实现判重功能;二是以一种不会重复的方式生成block id,比如顺序生成。顺序生成的缺点有3个,1是现有的系统迁移困难,所有的block都要重新命名;2是用完了64位数后仍然有麻烦;3是要记录好最高的block id。[1]暂时实现了判重功能。

判重并不是最优的方法,因为它需要额外的工作,而且随着文件系统变得庞大将变重。假设用一个Hash实现判重,一个1PB的文件系统,假设1个block大小64MB,则包含有16M个block id,每个id为8个byte,则需要一个128MB的Hash表,这对于一个本身就很复杂的NameNode是个不小的压力。[2]中提出了一种综合的方法,给一个文件的所有block指定一个相同的range id(5个byte)作为它们block id的高位,然后按顺序每个block生成剩余的3个byte。较之前的单纯判重,好处在于减小了判重的数量;同时又方便管理同一个文件的block,因为它们的block id是连续的。[2]也指出这种方法的问题,当一个文件被删除时,此range id要从系统中抹去,如果此时某个包含此文件某block的数据结点掉线了,在它重新上线之后,它又带回这个已经无效的range id。所以需要timestamps,即creation time of the file,当两个文件碰巧有相同的range id时,根据timestamps来判定谁是最新的文件,旧的文件将被删除。[2]中能看到Doug Cutting和Sameer Paranjpye的一些其它討論,比如range-id也采用顺序生成(又回到随机VS顺序的问题上)。

[1]和[2]都是在07年的0.1版本上的討論,现在0.20.2的版本是什么情况呢?我们先来看一下代码吧!FSNamesystem的allocateBlock方法:

  private Block allocateBlock(String src, INode[] inodes) throws IOException {
    Block b = new Block(FSNamesystem.randBlockId.nextLong(), 0, 0); 
    while(isValidBlock(b)) {
      b.setBlockId(FSNamesystem.randBlockId.nextLong());
    }
    b.setGenerationStamp(getGenerationStamp());
    b = dir.addBlock(src, inodes, b);
    NameNode.stateChangeLog.info("BLOCK* NameSystem.allocateBlock: "
                                 +src+ ". "+b);
    return b;
  }

这里block id还是用一个随机产生器生成的,并且用一个Map来判重,并没有上面提到的range id的概念。同时,赋与block一个GenerationStamp,此stamp是文件系统里的全局变量,会在每次创建新文件及其它一些block操作时顺序增长。关于它的具体作用是不是[2]中所提到的,还需要进一步阅读代码。而关于block id的顺序生成的问题上,今年在[3]中又有了新的討論,可能要等到0.23.0的版本才能看到結果吧。

参考:
[1] potential conflict in block id's, leading to data corruption
    https://issues.apache.org/jira/browse/HADOOP-146
[2] dfs should allocate a random blockid range to a file, then assign ids sequentially to blocks in the file
    https://issues.apache.org/jira/browse/HADOOP-158
[3] Sequential generation of block ids
    https://issues.apache.org/jira/browse/HDFS-898

posted on 2012-09-16 16:01  aaronwxb  阅读(2008)  评论(0编辑  收藏  举报