-
输入:
-
输入文件会被切分成多个切片,每一个切片交给一个map task进程来读取,默认每个block对应一个切片。
-
默认的Textinputformat以行为单位进行读取,每行数据返回一个键值对,将行号为key,行文本作为value,交给map函数处理。
因为如果一个切片包含了多个block,会存在maptask读取数据跨网络传输,不利于数据本地化的实现。
-
map:
-
在每个maptask中,有一个map函数,基于每行数据得到的键值对进行处理,得到新的键值对,通过context.write方法会将k2 v2写入到环形缓冲区中。
-
有多少个key-value对,就调用多少次Map函数。
-
shuffle阶段
-
我们知道,每个maptask会将map阶段输出数据写入本机的环形缓冲区中,环形缓冲区中的数据进行溢写 排序 合并等操作形成临时文件传输给reduce端,最终交给reduce函数来处理。
-
shuffle阶段整体分为分区 排序 规约 分组 四个步骤,但是每个步骤并不是单独进行的。
-
分区:
将一个maptask的数据分成多个分区,每个分区对应一个reducetask。
对于自定义分区操作,会为每一个key生成一个分区编号,在排序的时候会先按照分区编号排序,再按照key排序,从而完成了分区的逻辑。
-
排序
每一个maptask中的同一个分区的数据会按照map阶段输出的key进行排序。可以通过重写比较器自定义排序。
排序的过程是分阶段进行的,在溢写之前,map端合并,reduce端合并的过程中都会进行排序。
-
规约
对数据进行局部汇总,减少网络数据传输,提高效率。(规约要符合业务要求,求和可以规约,求平均值不可以)
由于规约是基于map端所有数据进行局部汇总的,因为也是分多个阶段完成的,在溢写之前,map端合并,reduce端合并的过程中都会进行规约。
-
传输
maptask与reducetask之间有一个数据分发过程,每个maptask的各分区数据会发送到各自对应的reducetask端。
实际过程是reduce端主动从map端拉取数据,先放在缓存中,逐步溢写 合并 得到临时文件。
-
分组
分组的过程在reducetask端完成,每个reducetask将接收到的当前分区的数据进行分组
相同 Key 的 Value 放入一个集合中组成新的集合形式的value。
因为在分组前一个分区内部的key已经排好序了,所以实现时依次比较相邻各个key,相同就放在一个分组,下一个key不同就另起一个分组。
-
reduce阶段
基于分组得到的每个key和对应value集合,进行聚合逻辑,最终得到新的键值对
然后通过context.write方法将键值对写入到hdfs文件中
-
输出阶段
TextOutputFormat类将每一个k4-v4对作为一行进行输出,默认一个分区写一个文件
mapreduce整体流程图解 三个maptask,两个reducetask
-
如下是mapreduce整体流程的图示
maptask
reducetask