假设您只有 1GB 的堆大小可用于每个映射器,但是 block 大小设置为 10GB,每个拆分为 10GB。映射器如何读取较大的个体拆分?
映射器会将输入缓冲到磁盘中并以循环方式处理输入拆分吗?
谢谢!
最佳答案
映射器的整体模式非常简单:
while not end of split
(key, value) = RecordReader.next()
(keyOut, valueOut) = map(key, value)
RecordWriter.write(keyOut, valueOut)
通常前两个操作只关心记录的大小。例如,当 TextInputFormat
被要求输入下一行时,它将字节存储在缓冲区中,直到找到下一行结束为止。然后缓冲区被清除。等等
map 实现由您决定。如果你不把东西存储在你的映射器中,那么你就没事了。如果您希望它是有状态的,那么您可能会遇到麻烦。确保您的内存消耗是有限的。
在最后一步中,映射器写入的键和值存储在内存中。然后对它们进行分区和排序。如果内存缓冲区变满,那么它的内容就会溢出到磁盘(无论如何最终都会溢出,因为即使在映射器消失后,reducers 也需要能够下载分区文件)。
所以你的问题的答案是:是的,会没事的。
可能引起麻烦的是:
- 大记录(指数缓冲区增长 + 内存副本 => 显着到疯狂的内存开销)
- 在映射器中存储来自先前键/值的数据
- 在自定义(输入|输出)格式实现中存储来自前一个键/值的数据(如果有的话)
如果您想了解更多,这里有几个切入点:
- 在Mapper.java你可以看到 while 循环
- 在LineRecordReader您可以看到
TextInputFormat
如何读取一行
- 您很可能想了解溢出机制,因为它会影响您的工作绩效。 See theses Cloudera slides例如。然后您将能够决定什么是您的用例的最佳设置(大分割与小分割)。
关于hadoop - hadoop 如何处理非常大的单个拆分文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25317050/