一个块信息包括:
1、块id
2、块大小
3、时间戳
4、这个快所属的文件是哪一个
5、这些块都存在哪些节点上
结合HDFS的底层实现来分析:
先来看一下Block类,它含 有三个成员:blockId,numBytes和generationStamp。numBytes即block的大小,blockId是block的标识符,可以从block文件名中看到,例如/export/data/hadoop/dfs/data/current/BP-1483015962-192.168.254.101-1536400451508/current/finalized/subdir0/subdir0/blk_1073741831,这一串数字就是blockId。同目录下另一个meta文件,如 blk_1073741831_1007.meta,1007即是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