我正在读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。
如果到目前为止,我的理解是正确的,