Hadoop - 不可分割文件不同大小(200-500mb)的适当块大小

10
如果我需要对大小在200到500MB之间变化的(不可分割的)数千个gzip文件进行连续扫描,那么这些文件的适当块大小是多少?
出于本问题的考虑,假设处理速度非常快,因此即使针对大块大小,重新启动映射器也不会很昂贵。
我的理解是:
1. 块大小几乎没有上限,因为对于我的集群大小,有足够数量的映射器适用于“大量文件”。 2. 为确保数据局部性,我希望每个gzip文件都在一个块中。
然而,gzipped文件的大小不同。如果我选择了~500MB(例如所有输入文件的最大文件大小)的块大小,数据将如何存储?选择“非常大”的块大小,例如2GB是否更好?在任一情况下,HDD容量是否被浪费过多?
我想我真正想知道的是文件实际上是如何存储和拆分的,以及如何获得对不可分割文件的最佳实践的理解。
更新:具体示例
假设我正在运行三个200 MB文件的MR作业,存储如下图所示。
如果HDFS像A案例中一样存储文件,则保证有3个映射器能够处理每个“本地”文件。但是,如果文件存储如B案例所示,则一个映射器将需要从另一个数据节点获取部分文件2。
考虑到有大量空闲块,HDFS会将文件存储为A案例或B案例中所示的方式?
2个回答

4
如果您有不可分割的文件,则最好使用更大的块大小,大小应与文件本身相同(或更大,没有区别)。
如果块大小小于总文件大小,则可能会出现所有块不在同一数据节点上的情况,从而失去数据位置性。如果是可分割文件,则这不是问题,因为每个块都将创建一个映射任务。
至于块大小的上限,我知道对于某些较旧版本的Hadoop,限制为2GB(超过此限制块内容将无法获得)-请参见https://issues.apache.org/jira/browse/HDFS-96 使用更大的块大小存储较小的文件没有任何缺点-为了强调这一点,请考虑具有2GB块大小的1MB和2GB文件:
  • 1 MB- 1个块,在Name Node中有单个条目,在每个数据节点副本上实际存储1 MB
  • 2 GB- 1个块,在Name node中有单个条目,在每个数据节点副本上实际存储2 GB
除了所需的物理存储外,名称节点块表没有任何缺点(两个文件在块表中都只有一个条目)。
唯一可能的缺点是复制较小块与较大块所需的时间不同,但反过来,如果从集群中丢失数据节点,则将2000个1 MB块复制到较慢的速度比单个2 GB块更慢。
更新-一个实际示例
由于这引起了一些混乱,这里有一些实际示例:
假设我们有一个300 MB的HDFS块大小系统,并且为了简化事情,我们只有一个数据节点的伪集群。
如果您想存储一个1100 MB的文件,那么HDFS将将该文件分成最多300 MB的块,并在数据节点上以特殊的块索引文件存储。如果您去查看数据节点并查看它在物理磁盘上存储索引块文件的位置,您可能会看到类似于这样的内容:
/local/path/to/datanode/storage/0/blk_000000000000001  300 MB
/local/path/to/datanode/storage/0/blk_000000000000002  300 MB
/local/path/to/datanode/storage/0/blk_000000000000003  300 MB
/local/path/to/datanode/storage/0/blk_000000000000004  200 MB

请注意,该文件并非完全可被300 MB整除,因此文件的最后一个块的大小是文件大小与块大小的模数。
现在,如果我们使用小于块大小的文件(比如1 MB)重复相同的操作,并查看它在数据节点上的存储方式:
/local/path/to/datanode/storage/0/blk_000000000000005  1 MB

请注意,存储在数据节点上的实际文件大小为1 MB,而不是带有299 MB零填充的200 MB文件(我认为混淆的原因在于此)。
现在块大小在效率方面发挥作用的地方是在名称节点。对于上述两个示例,名称节点需要维护文件名、块名和数据节点位置的映射(以及总文件大小和块大小)。
filename     index     datanode
-------------------------------------------
fileA.txt    blk_01    datanode1
fileA.txt    blk_02    datanode1
fileA.txt    blk_03    datanode1
fileA.txt    blk_04    datanode1
-------------------------------------------
fileB.txt    blk_05    datanode1

您可以看到,如果将文件A.txt 的块大小设置为1 MB,则需要在上述映射中使用1100个条目而不是4个(这将在名称节点中占用更多内存)。此外,检索所有块将更加昂贵,因为您需要向数据节点1发出1100个RPC调用,而不是4个。

如果我将3个200MB的文件存储在300MB的块中会发生什么?每第二个文件是否会跨越两个块,还是每个块都会留下100MB未使用?将块大小设置为max(filesize)max(filesize)*20可能会对性能(当文件不可分割时)或存储“浪费”(取决于文件实际如何分布在块中)产生巨大影响。 - jkgeyti
如果您使用300 MB块大小存储200 MB文件,则不会浪费任何空间。这与传统文件系统上的块大小不同,未使用的100 MB不会被浪费。在HDFS中唯一的低效率是,如果您使用太小的块大小存储大文件,则主要是Name Node的内存需求,以跟踪文件的每个块。 - Chris White
1
好的,我会尝试另一种方法 - 如果文件小于块大小,则它们将以与文件本身大小相同的文件大小存储在数据节点上。如果文件大于数据块,比如1100MB,那么你将有一些300MB的块(3 x 300 MB)存储在数据服务器上,剩余的200MB将作为一个200MB的文件存储在某个数据节点上。 - Chris White
没问题,但是针对你更新的问题,两种情况都不正确——从概念上来说,不要考虑将文件存储在固定大小的信鸽洞中,而是想象一下你的文件可以被切成块并进行处理。假设该文件可分割,则您将获得每个文件块的映射器(您的情况A是最接近的匹配)。 - Chris White
好的,我想我懂了。非常感谢您详尽地回答我的问题。非常感谢! - jkgeyti
显示剩余2条评论

1
我将试着通过示例来突出块分割在文件大小方面的差异。在HDFS中,您有:
Splittable FileA size 1GB
dfs.block.size=67108864(~64MB)

针对此文件的MapRed作业:

16 splits and in turn 16 mappers.

让我们来看一个使用压缩(不可分割)文件的场景:

Non-Splittable FileA.gzip size 1GB
dfs.block.size=67108864(~64MB)

对该文件进行MapRed作业:

16 Blocks will converge on 1 mapper.

最好主动避免这种情况,因为这意味着任务跟踪器将不得不获取大多数不属于任务跟踪器的16个数据块。
最后,块、拆分和文件之间的关系可以总结如下:
                                                             block boundary
|BLOCK           |    BLOCK       |   BLOCK        |   BLOCK ||||||||
|FILE------------|----------------|----------------|---------|
|SPLIT            |                |                |        |

分割可以扩展到块之外,因为分割取决于InputFormat类定义如何分割文件,可能与块大小不一致,因此分割会扩展以包括源内的寻址点。

这非常有帮助,谢谢。我能问你和我问Chris White一样的问题吗?如果我将3个200 MB文件存储在300 MB块中会发生什么?每第二个文件是否会分割成两个块,还是每个块都会留下100 MB未使用? - jkgeyti
看起来Chris在评论中很好地回答了你问我的问题,但是这里的关键点是,与传统文件系统不同,HDFS有效地利用其空间,因此块遵守文件大小的逻辑边界而不浪费空间。 - Engineiro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接