2010-06-10 116 views
2

我正在开发应用程序以使用Hadoop框架处理(和合并)几个大型Java序列化对象(大小为GB)。 Hadoop商店在不同的主机上分发文件的块。但是,由于反序列化需要所有的块都存在于单个主机上,所以它会大幅度地提升性能。与文本文件不同,我怎样才能处理这种情况:不同的块必须不能单独处理?Hadoop:处理大型序列化对象

回答

3

有两个问题:一个是每个文件都必须(在初始阶段)被整个处理:看到第一个字节的映射器必须处理该文件的所有其余部分。另一个问题是局部性:为了获得最佳效率,你希望每个这样的文件的所有块都驻留在同一个主机上。在整个


处理文件:

一个简单的窍门是让第一阶段的映射过程的文件名,而不是其内容的列表。如果您想要运行50个地图作业,请使用这部分文件名制作50个文件。这很容易,可以与java或流式传输hadoop一起使用。

或者,使用不可拆分的输入格式,例如NonSplitableTextInputFormat

有关更多详细信息,请参阅hadoop wiki上的“How do I process files, one per map?”和“How do I get each of my maps to work on one complete input-file?”。


地点:

这留下一个问题,但是,你正在阅读的块都跨HDFS disributed:通常是性能增益,这里真正的问题。我不相信有任何方法可以将特定的块连接在HDFS中。

是否可以将文件放置在每个节点的本地存储中?这实际上是解决这个问题的最高性能和最简单的方法:让每台机器启动作业以处理例如文件中的所有文件。 /data/1/**/*.data(与你关心的高效使用本地分区和CPU核心数一样聪明)。

如果这些文件来自SAN或来自说s3,那就试试直接从那里拉出来:它的目的是为了处理群体。


使用第一招的说明:如果某些文件是比别人大的多,把他们独自在最早命名的上市,以避免投机性执行力的问题。无论如何,如果任务可靠并且您不希望某些批次处理多次,则可以关闭此类作业的投机执行。

2

我认为基本的(无益的)答案是你不能真正做到这一点,因为它直接违背了MapReduce范例。映射器和减速器的输入和输出单位是相对较小的记录。 Hadoop在这些方面运行,而不是磁盘上的文件块。

你确定你的进程需要一台主机上的所有东西吗?任何我想描述为合并的东西都可以像MapReduce那样相当干净地实现,并且没有这样的要求。

如果您希望确保某些键(及其值)最终位于同一个缩减器上,则可以使用Partitioner来定义键映射到reducer实例的方式。根据你的情况,这可能是你真正的追求。

我也会说你听起来像是在试图对HDFS文件进行操作,而不是编写Hadoop MapReduce。所以也许你的问题真的是关于如何在HDFS上打开几个SequenceFile s,手动读取它们的记录并合并。这并不是一个Hadoop问题,但是,仍然不需要在一台主机上安装块。

+0

让我来重述一下我的问题。因此,通常在输入文件中能够被Mapper函数(如在文本文件中)进行部分读取和处理。就我而言,我打算使用2个Mapper函数,第一个将二进制文件分成较小的(键,值)对,第二个用于更传统的Mapper目的。我的问题是我能做些什么来处理二进制文件(比如说图像,序列化对象),这将需要所有的块在同一主机上,然后才能开始处理。希望能解释我的问题。我感谢你的回应。 – restrictedinfinity 2010-06-10 08:47:38

+1

我不认为这需要所有块在一台主机上。它确实要求工作人员从HDFS传输足够的块以读取至少一个完整的记录。但无论如何,数据必须最终到达工作人员。我想说让HDFS来处理它。 – 2010-06-10 10:58:24

3

听起来你的输入文件是一个大的序列化对象。是这样吗?你可以用一个简单的键使每个项目具有自己的序列化值吗?例如,如果您想要使用Hadoop并行调整图像大小,您可以逐个序列化每个图像并使用简单的索引键。您的输入文件将是一个文本文件,其中键值对是索引键,然后序列化的blob将是该值。

在Hadoop中进行模拟时,我使用这种方法。我的序列化的blob是模拟所需的所有数据,关键仅仅是表示模拟编号的整数。这使我可以像Grid Engine一样使用Hadoop(特别是Amazon Elastic Map Reduce)。