【发布时间】:2014-10-22 07:00:40
【问题描述】:
我正在编写一个 hadoop MapReduce 作业,该作业在完整的 Debian 镜像(≈ 40 GB)的所有源代码文件上运行。由于 Debian 镜像数据在单独的机器上,而不是在 hadoop 集群中,所以第一步是下载数据。
我的第一个实现下载一个文件并输出 key=$debian_package, value=$file_contents。然后应将每个键的各种值(通常为 4)减少为单个条目。下一个 MapReduce 作业将作为键操作 debian 包,并将其所有文件作为值操作。
但是,我注意到 hadoop 在输出值有时可能非常大(700 MB 是我见过的最大的)时效果不佳。在 MapReduce 框架的各个地方,整个文件都存储在内存中,有时是两倍甚至三倍。我经常遇到内存不足错误,即使 Java 堆大小为 6 GB。
现在我想知道如何拆分数据,以便更好地匹配 hadoop 的 64 MB 块大小。
我不能简单地将大文件分成多个部分,因为它们是压缩的(tar/bz2、tar/xz、tar/gz,也许将来还会有其他文件)。在我对它们进行 dpkg-source 以将包作为一个整体提取(必要!)之前,文件需要保持其完整大小。
我想到的一个想法是将文件存储在第一个 MapReduce 中的 hdfs 上,并且只将它们的路径传递给第二个 MapReduce。但是,那我绕过了 hadoop 对数据局部性的支持,或者有没有办法解决这个问题?
还有其他我遗漏的技术吗?你有什么推荐的?
【问题讨论】:
-
我很确定 Hadoop 在输出值时并不是很差,而是您发出的输出字符串超出了您的内存大小。
-
是什么让你如此确定?我正在输出 BytesWritable 对象并将它们缩减为 ArrayWritable。多重分配问题的一个实例是hadoop.apache.org/docs/r2.3.0/api/src-html/org/apache/hadoop/io/…(1.5 倍放大),另一个是grepcode.com/file/repository.cloudera.com/content/repositories/…(2 倍最大值大小分配)。还有更多我没有挖掘的东西。我确信 hadoop 不是为/测试了 500 MB+ 的输出值。
-
实现你自己的
BytesWritable不会浪费在调整大小上(为什么你首先要调整大小?)。通常大于 64mb 缓冲区的记录会立即溢出到磁盘。不知道为什么要发出 500 mb 的记录。 -
我没有明确地调整大小,这个方法在反序列化时自动调用(即馈送到 Reducer)。我知道大记录会立即泄露。我想我解释了为什么 500 MB 记录:一些源 tarball 非常大(例如 500 MB),我需要将它们从第一个 MapReduce(下载)到第二个 MapReduce(解压缩),然后才能拆分它们。跨度>