Hadoop:处理大型序列化对象

我正在开发一个应用程序来使用Hadoop框架处理(并合并)几个大型java序列化对象(订单GB的大小)。 Hadoop存储在不同主机上分发文件块。 但是由于反序列化将要求所有块都出现在单个主机上,因此它会大大提高性能。 与文本文件不同,我如何处理不同块无法单独处理的情况?

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


整个处理文件:

一个简单的技巧是让第一阶段映射器处理文件名列表 ,而不是其内容。 如果要运行50个映射作业,请使用该部分文件名制作50个文件。 这很容易,适用于java或流式hadoop。

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

有关更多详细信息,请参阅hadoop wiki上的“ 如何处理文件,每个地图一个? ”和“ 如何让每个地图在一个完整的输入文件上工作? ”。


地点:

然而,这留下了一个问题,即您正在读取的块在整个HDFS中被分配:通常是性能提升,这是一个真正的问题。 我不相信有任何方法可以将某些块链接在HDFS中一起旅行。

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

如果文件来自SAN或者说来自s3,请尝试直接从那里拉出:它是为了处理群而构建的。


关于使用第一个技巧的说明:如果某些文件比其他文件大得多,请将它们单独放在最早命名的列表中,以避免推测执行的问题。 如果任务可靠并且您不希望多次处理某些批次,则可能无论如何都会关闭此类作业的推测执行。

听起来你的输入文件是一个大的序列化对象。 是这样的吗? 你能用一个简单的密钥使每个项目都有自己的序列化值吗?

例如,如果您想使用Hadoop并行调整图像大小,可以单独序列化每个图像并使用简单的索引键。 您的输入文件将是一个文本文件,其中键值对是索引键,然后序列化的blob将是值。

我在Hadoop中进行模拟时使用此方法。 我的序列化blob是模拟所需的所有数据,键只是一个表示模拟数的整数。 这允许我像网格引擎一样使用Hadoop(特别是Amazon Elastic Map Reduce)。

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

您确定您的流程需要一台主机上的所有内容吗? 我描述为合并的任何东西都可以非常干净地实现为没有这种要求的MapReduce。

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

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