10

如果我需要对(不可分割的)数千个大小在 200 到 500mb 之间的 gzip 文件进行顺序扫描,这些文件的合适块大小是多少?

对于这个问题,假设处理完成的速度非常快,因此重新启动映射器并不昂贵,即使对于大块大小也是如此。

我的理解是:

  1. 块大小几乎没有上限,因为对于我的集群大小而言,适当数量的映射器有“大量文件”。
  2. 为了确保数据局部性,我希望每个 gzip 文件都在 1 个块中。

但是,gzip 压缩的文件大小不一。如果我选择 ~500mb 的块大小(例如我所有输入文件的最大文件大小),如何存储数据?选择一个“非常大”的块大小会更好吗,比如 2GB?在这两种情况下是否过度浪费了 HDD 容量?

我想我真的在问文件是如何在 hdfs 块之间实际存储和拆分的——以及试图了解不可拆分文件的最佳实践。

更新:一个具体的例子

假设我正在三个 200 MB 文件上运行 MR 作业,存储如下图所示。

如果 HDFS 像案例 A 那样存储文件,则可以保证 3 个映射器每个都能够处理一个“本地”文件。但是,如果文件按照情况 B 存储,则一个映射器将需要从另一个数据节点获取文件 2 的一部分。

鉴于有大量空闲块,HDFS 是按照案例 A 还是案例 B 存储文件?

HDFS 策略

4

2 回答 2

4

如果您有不可拆分的文件,那么您最好使用更大的块大小 - 与文件本身一样大(或更大,没有区别)。

如果块大小小于整体文件大小,那么您可能会遇到所有块并不都在同一个数据节点上并且您丢失数据局部性的可能性。这不是可拆分文件的问题,因为将为每个块创建一个映射任务。

至于块大小的上限,我知道对于某些旧版本的 Hadoop,限制是 2GB(超过该块内容是无法获得的) - 请参阅https://issues.apache.org/jira/browse/HDFS- 96

存储具有较大块大小的较小文件没有缺点 - 为了强调这一点,考虑一个 1MB 和 2 GB 的文件,每个文件的块大小为 2 GB:

  • 1 MB - 1 个块,名称节点中的单个条目,1 MB 物理存储在每个数据节点副本上
  • 2 GB - 1 个块,名称节点中的单个条目,每个数据节点副本上物理存储 2 GB

因此,除了所需的物理存储之外,名称节点块表没有缺点(两个文件在块表中都有一个条目)。

唯一可能的缺点是复制较小块与较大块所需的时间,但另一方面,如果数据节点从集群中丢失,则任务复制 2000 x 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,而不是200 MB 的文件,299 MB 的零填充(我认为这是混乱的来源)。

现在,块大小确实影响效率的地方在于名称节点。对于上面的两个例子,name node 需要维护一个文件名的映射,到块名和数据节点位置(以及总文件大小和块大小):

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

您可以看到,如果您要为 fileA.txt 使用 1 MB 的块大小,则上述映射中需要 1100 个条目而不是 4 个(这将需要名称节点中的更多内存)。此外,撤回所有块会更昂贵,因为您将对 datanode1 进行 1100 次 RPC 调用而不是 4 次。

于 2013-06-22T12:39:55.960 回答
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.

最好主动避免这种情况,因为这意味着 tasktracker 将必须获取 16 个数据块,其中大部分不是 tasktracker 本地的。

最后,block、split和file的关系可以总结如下:

                                                             block boundary
|BLOCK           |    BLOCK       |   BLOCK        |   BLOCK ||||||||
|FILE------------|----------------|----------------|---------|
|SPLIT            |                |                |        |

拆分可以扩展到块之外,因为拆分取决于如何拆分文件的 InputFormat 类定义,该文件可能与块大小不一致,因此拆分超出范围以包括源中的查找点。

于 2013-06-22T15:13:52.740 回答