6

我正在读Hadoop: The definitive guide 3rd edtition汤姆·怀特的书。它是了解 内部结构的绝佳资源Hadoop,尤其是Map-Reduce我感兴趣的内部结构。

从书中,(第205页):

随机和排序

MapReduce 保证每个 reducer 的输入都是按键排序的。系统执行排序并将 map 输出作为输入传输到 reducer 的过程称为 shuffle。

我由此推断,key在发送到reducer之前是先排序的,说明job的map阶段的输出是排序的。请注意:我不叫它映射器,因为映射阶段包括映射器(由程序员编写)和 MR 框架的内置排序机制。


地图侧

每个映射任务都有一个循环内存缓冲区,它会将输出写入其中。缓冲区默认为 100 MB,可以通过更改 io.sort.mb 属性来调整大小。当缓冲区的内容达到某个阈值大小(io.sort.spill.percent,默认为 0.80 或 80%)时,后台线程将开始将内容溢出到磁盘。在溢出发生时,映射输出将继续写入缓冲区,但如果在此期间缓冲区填满,映射将阻塞,直到溢出完成。
在写入磁盘之前,线程首先将数据划分为reducers对应的分区他们最终将被发送到。在每个分区内,后台线程按键执行内存排序,如果有组合器函数,则在排序的输出上运行。运行 combiner 函数可以得到更紧凑的 map 输出,因此写入本地磁盘和传输到 reducer 的数据更少。

我对上一段的理解是,在mapper产生键值对的过程中,键值对是被分区和排序的。一个假设的例子:

考虑将 mapper-1 用于字数统计程序:

>mapper-1 contents
partition-1
   xxxx: 2
   yyyy: 3
partition-2
   aaaa: 15
   zzzz: 11

(注意with-in每个分区的数据都是key排序的,但是partition-1的数据和partition-2的数据不一定要按顺序排列)


继续阅读本章:

每次内存缓冲区达到溢出阈值时,都会创建一个新的溢出文件,因此在映射任务写入其最后一个输出记录后,可能会有多个溢出文件。在任务完成之前,溢出文件被合并成一个单独的分区和排序的输出文件。配置属性 io.sort.factor 控制一次合并的最大流数;默认值为 10。

我的理解是(请知道上面段落中的粗体短语,这欺骗了我):在一个映射任务中,几个文件可能会溢出到磁盘,但它们会合并到一个仍然包含分区并已排序的文件中。考虑与上面相同的示例:

在单个地图任务完成之前,它的中间数据可能是:

mapper-1 内容

spill 1:             spill 2:           spill 2:
    partition-1         partition-1        partition-1
                          hhhh:5       
       xxxx: 2            xxxx: 3             mmmm: 2
       yyyy: 3            yyyy: 7             yyyy: 9 

    partition-2         partition-2        partition-2
       aaaa: 15           bbbb: 15            cccc: 15
       zzzz: 10           zzzz: 15            zzzz: 13

map-task 完成后,mapper 的输出将是一个文件(注意现在添加了上面的三个溢出文件,但假设作业 conf 中没有指定组合器,则没有应用组合器):

>Mapper-1 contents:
partition-1:
hhhh: 5
mmmm: 2
xxxx: 2
xxxx: 3
yyyy: 3
yyyy: 7
yyyy: 9
partition-2:
aaaa: 15
bbbb: 15
cccc: 15
zzzz: 10
zzzz: 15
zzzz: 13

所以这里partition-1可能对应reducer-1。即上面partition-1段对应的数据被发送到reducer-1,partition-2段对应的数据被发送到reducer-2。

如果到目前为止,我的理解是正确的,

  1. 我将如何从映射器输出中获取具有分区和排序数据的中间文件。
  2. 有趣的是,单独运行 mapper 不会产生排序输出,这与发送到 reducer 的数据未排序点相矛盾。更多细节在这里
  3. 如果 No only Mapper 运行,甚至没有应用组合器:更多细节在这里
4

1 回答 1

8

Map-only 作业与 Map-and-Reduce 作业的工作方式不同。没有矛盾,只是不同。

我将如何从映射器输出中获取具有分区和排序数据的中间文件。

你不能。没有钩子可以从 MapReduce 的中间阶段获取数据片段。在分区器之后或在记录读取器之后获取数据等也是如此。

有趣的是,单独运行 mapper 不会产生排序输出,这与发送到 reducer 的数据未排序的点相矛盾。更多细节在这里

这并不矛盾。Mappers 排序是因为 reducer 需要对它进行排序才能进行合并。如果没有减速器,它就没有理由进行排序,所以它没有。这是正确的行为,因为我不希望它在仅地图作业中排序,这会使我的处理速度变慢。我从来没有遇到过我希望我的地图输出在本地排序的情况。

如果 No only Mapper 运行,甚至没有应用组合器:更多细节在这里

组合器是一种优化。无法保证它们实际运行或超过了哪些数据。组合器主要用于使减速器更有效。所以,再一次,就像本地排序一样,如果没有减速器,组合器就不会运行,因为它没有理由这样做。

如果您想要类似组合器的行为,我建议将数据写入缓冲区(可能是哈希图),然后在 Mapper 完成时运行的清理函数中写出本地汇总的数据。如果要执行此操作,请注意内存使用情况。这是一种更好的方法,因为组合器被指定为一种很好的优化,您不能指望它们运行......即使它们确实运行。

于 2014-07-23T18:30:36.893 回答