我正在努力理解mapreduce中的数据流。最近,当我的磁盘在reduce阶段内存不足时,一个非常苛刻的工作崩溃了。我发现很难估计我的工作需要多少磁盘。我将详细描述数据流。
如果有人能够纠正,详细说明mapreduce中的数据流或提供有关系统尺寸的建议,那将会很有帮助。
我有一个包含 30个奴隶和
的群集我的地图任务与wordcount非常相似,因此它们需要很少的内存。我的减少任务适用于排列组的单词。由于需要连接相同的单词,reduce函数需要一个临时的哈希映射,该映射总是<= 3GB。
由于我有12GB的RAM而且我的hadoop守护进程需要1GB的堆+ 500MB用于操作系统,我将map / reduce插槽划分如下:
4个映射插槽,堆栈为900MB , 2个耗尽3GB堆的插槽。由于映射插槽不需要超过300MB的内存,因此我将io.sort.mb
设置为500 MB,以改善映射阶段的内存排序。
我的工作有 1800个地图任务,每个任务产生8 GB的地图输出。由于我使用BZIP2进行压缩,因此可以将其压缩为1 GB。这意味着总地图输出将低于2 TB ,而我有3 TB的内存。
我选择了100个减少任务,每个任务产生5 GB的输出。
乍一看,一切都应该适合记忆。但显然排序阶段需要压缩和解压缩,复制阶段要求数据同时位于2个位置(我假设)。所以这里是棘手的,这就是为什么我想完全理解数据流的原因。这就是我认为它的工作原理,但如果我错了,请纠正我:地图任务会在内存中生成大量溢出(在我的情况下为200)排序,然后在写入之前压缩到本地磁盘。地图任务完成后,会为我提供200个溢出文件,每10个文件合并(io.sort.factor
)。
这意味着10个文件解压缩:10 x(5MB - > 40MB),因此这会产生0.4GB的压缩/解压缩开销。虽然我不确定200次泄漏后他们的第一次合并回合会发生什么。我想他们每次减少任务都会被洗牌?因此文件的大小不会增加太多。
如果我们从黑盒的角度来看这意味着我们从200个压缩的溢出开始,我们最终会有100个压缩文件用于reduce任务(每个任务1个)。
由于我只有60个reducer,现在每个节点 60个压缩文件被复制到reducers ,这已经在map阶段完成了。这可能意味着压缩文件暂时存在于源和目标上。这意味着在这种情况下,每个节点的内存需求(临时)上升160个压缩文件,这是地图输出的1.6倍。 地图输出为1800 GB ,因此我们最终会得到2880 GB,尽管是暂时的。所以第一个减少阶段应该能够启动而且确实如此。复制后(我希望!)数据从地图输出目录中删除,因此我们拥有与地图输出相同的数据量,再次为1800 GB。
现在减速器中的排序阶段开始了。我希望它不会在映射器的内存被清除之前启动吗?!由于要合并1800个映射任务的输出,因此必须对其进行解压缩。减少任务的输入大约是mapoutput / 100 = 18 GB的压缩数据。现在如何解压缩,它不能一次解压缩,因为那时每个节点有144GB,而且由于我的工作没有崩溃,所以解压缩的执行稍微聪明一些。我会以与地图阶段相同的方式思考:10个文件(1800个任务输出)被同时解压缩和合并。然后,解压缩将在每次合并轮次中产生18GB / 180 = 100MB的开销。问题是最后一次合并轮次是如何发生的,我记得在hadoop引用中读到减压器不会继续合并,直到只剩下一个文件。
在reduce阶段进行排序之后,reduce阶段会运行,这需要对输入记录进行解压缩,但由于每个reduce任务都使用500个输入密钥组,因此这不应该是一个真正的问题。
如前所述,reduce任务为DFS产生大约5GB的输出(总共0.5TB)。
在前60个减少任务完成后,工作确实遇到了麻烦。在第二轮中,任务在排序阶段开始崩溃,这使我认为它与复制开销或解压缩开销有关。
确切的例外是:org.apache.hadoop.util.DiskChecker$DiskErrorException: Could not find any valid local directory for attempt_201310160819_0001_r_000068_1/intermediate.3
我希望我能够详细解释我的程序流程以及对mapreduce的理解。我真的很感激,如果:
例外1:
org.apache.hadoop.util.DiskChecker$DiskErrorException: Could not find any valid local directory for attempt_201310160819_0001_r_000068_1/intermediate.3
at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.getLocalPathForWrite(LocalDirAllocator.java:381)
at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:146)
at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:127)
at org.apache.hadoop.mapred.Merger$MergeQueue.merge(Merger.java:510)
at org.apache.hadoop.mapred.Merger.merge(Merger.java:142)
at org.apache.hadoop.mapred.ReduceTask$ReduceCopier.createKVIterator(ReduceTask.java:2539)
at org.apache.hadoop.mapred.ReduceTask$ReduceCopier.access$400(ReduceTask.java:661)
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:399)
at org.apache.hadoop.mapred.Child$4.run(Child.java:255)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:416)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1190)
at org.apache.hadoop.mapred.Child.main(Child.java:249)
例外2:
FAILEDjava.io.IOException: Task: attempt_201310160819_0001_r_000075_1 - The reduce copier failed
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:390)
at org.apache.hadoop.mapred.Child$4.run(Child.java:255)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:416)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1190)
at org.apache.hadoop.mapred.Child.main(Child.java:249)
Caused by: org.apache.hadoop.util.DiskChecker$DiskErrorException: Could not find any valid local directory for output/map_1622.out
at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.getLocalPathForWrite(LocalDirAllocator.java:381)
at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:146)
at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:127)
at org.apache.hadoop.mapred.MapOutputFile.getInputFileForWrite(MapOutputFile.java:176)
at org.apache.hadoop.mapred.ReduceTask$ReduceCopier$InMemFSMergeThread.doInMemMerge(ReduceTask.java:2798)
at org.apache.hadoop.mapred.ReduceTask$ReduceCopier$InMemFSMergeThread.run(ReduceTask.java:2762)
异常3 :(可能是由磁盘检查程序异常引起的)
Task attempt_201310160819_0001_r_000077_1 failed to report status for 2400 seconds. Killing!
答案 0 :(得分:0)
我刚从Praveen Sripati收到一封关于hadoop参考的电子邮件,我会将其粘贴在这里:
在复制阶段,数据是否同时存在于map和reduce任务中?地图输出何时清除?
以下内容来自Hadoop - The Definitive Guide
第一个reducer时,主机不会从磁盘中删除映射输出 已经检索到它们,因为减速器可能随后失败。代替, 他们等到被告知他们被职员追踪者删除(或者 应用程序主),即作业完成后。
这非常重要,地图输出仍保留在磁盘上!在我的情况下有点不幸。
5)然后减速器中的合并开始。不完全确定它是如何完成的。它是否每个reduce键合并为一个文件?或者它是否合并了一项任务的所有内容?
再次来自同一本书
复制完所有地图输出后,reduce任务将进入 排序阶段(应该恰当地称为合并阶段,如 排序是在地图一侧进行的,它合并了地图 输出,保持排序顺序。这是轮次完成的。对于 例如,如果有50个地图输出,并且合并因子是10( 默认值,由io.sort.factor属性控制,就像在 地图的合并),将有五轮。每轮合并10 文件合为一个,所以最后会有五个中间文件。
谢谢,Praveen
这意味着合并后的文件数量仅限于io.sort.factor。在我的情况下,有10个细分,每个1.8GB。在上次合并期间,所有内容都必须解压缩,因此每轮需要1.8 * 10 GB = 18 GB。